- Initial checkin of the freebios2 tree

git-svn-id: svn://svn.coreboot.org/coreboot/trunk@784 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
This commit is contained in:
Eric Biederman 2003-04-22 19:02:15 +00:00
parent b138ac83b5
commit 8ca8d7665d
109 changed files with 13965 additions and 0 deletions

182
src/arch/i386/boot/boot.c Normal file
View File

@ -0,0 +1,182 @@
#include <console/console.h>
#include <ip_checksum.h>
#include <boot/elf.h>
#include <boot/elf_boot.h>
#include <string.h>
#ifndef CMD_LINE
#define CMD_LINE ""
#endif
#define UPSZ(X) ((sizeof(X) + 3) &~3)
static struct {
Elf_Bhdr hdr;
Elf_Nhdr ft_hdr;
unsigned char ft_desc[UPSZ(FIRMWARE_TYPE)];
Elf_Nhdr bl_hdr;
unsigned char bl_desc[UPSZ(BOOTLOADER)];
Elf_Nhdr blv_hdr;
unsigned char blv_desc[UPSZ(BOOTLOADER_VERSION)];
Elf_Nhdr cmd_hdr;
unsigned char cmd_desc[UPSZ(CMD_LINE)];
} elf_boot_notes = {
.hdr = {
.b_signature = 0x0E1FB007,
.b_size = sizeof(elf_boot_notes),
.b_checksum = 0,
.b_records = 4,
},
.ft_hdr = {
.n_namesz = 0,
.n_descsz = sizeof(FIRMWARE_TYPE),
.n_type = EBN_FIRMWARE_TYPE,
},
.ft_desc = FIRMWARE_TYPE,
.bl_hdr = {
.n_namesz = 0,
.n_descsz = sizeof(BOOTLOADER),
.n_type = EBN_BOOTLOADER_NAME,
},
.bl_desc = BOOTLOADER,
.blv_hdr = {
.n_namesz = 0,
.n_descsz = sizeof(BOOTLOADER_VERSION),
.n_type = EBN_BOOTLOADER_VERSION,
},
.blv_desc = BOOTLOADER_VERSION,
.cmd_hdr = {
.n_namesz = 0,
.n_descsz = sizeof(CMD_LINE),
.n_type = EBN_COMMAND_LINE,
},
.cmd_desc = CMD_LINE,
};
int elf_check_arch(Elf_ehdr *ehdr)
{
return (
((ehdr->e_machine == EM_386) || (ehdr->e_machine == EM_486)) &&
(ehdr->e_ident[EI_CLASS] == ELFCLASS32) &&
(ehdr->e_ident[EI_DATA] == ELFDATA2LSB)
);
}
void jmp_to_elf_entry(void *entry, unsigned long buffer)
{
extern unsigned char _ram_seg, _eram_seg;
unsigned long lb_start, lb_size;
unsigned long adjust, adjusted_boot_notes;
unsigned long type;
elf_boot_notes.hdr.b_checksum =
compute_ip_checksum(&elf_boot_notes, sizeof(elf_boot_notes));
type = 0x0E1FB007;
lb_start = (unsigned long)&_ram_seg;
lb_size = (unsigned long)(&_eram_seg - &_ram_seg);
adjust = buffer + lb_size - lb_start;
adjusted_boot_notes = (unsigned long)&elf_boot_notes;
adjusted_boot_notes += adjust;
printk_spew("entry = 0x%08lx\n", (unsigned long)entry);
printk_spew("lb_start = 0x%08lx\n", lb_start);
printk_spew("lb_size = 0x%08lx\n", lb_size);
printk_spew("adjust = 0x%08lx\n", adjust);
printk_spew("buffer = 0x%08lx\n", buffer);
printk_spew(" elf_boot_notes = 0x%08lx\n", (unsigned long)&elf_boot_notes);
printk_spew("adjusted_boot_notes = 0x%08lx\n", adjusted_boot_notes);
/* Jump to kernel */
__asm__ __volatile__(
" cld \n\t"
/* Save the callee save registers... */
" pushl %%esi\n\t"
" pushl %%edi\n\t"
" pushl %%ebx\n\t"
/* Save the parameters I was passed */
" pushl $0\n\t" /* 20 adjust */
" pushl %0\n\t" /* 16 lb_start */
" pushl %1\n\t" /* 12 buffer */
" pushl %2\n\t" /* 8 lb_size */
" pushl %3\n\t" /* 4 entry */
" pushl %4\n\t" /* 0 elf_boot_notes */
/* Compute the adjustment */
" xorl %%eax, %%eax\n\t"
" subl 16(%%esp), %%eax\n\t"
" addl 12(%%esp), %%eax\n\t"
" addl 8(%%esp), %%eax\n\t"
" movl %%eax, 20(%%esp)\n\t"
/* Place a copy of linuxBIOS in it's new location */
/* Move ``longs'' the linuxBIOS size is 4 byte aligned */
" movl 12(%%esp), %%edi\n\t"
" addl 8(%%esp), %%edi\n\t"
" movl 16(%%esp), %%esi\n\t"
" movl 8(%%esp), %%ecx\n\n"
" shrl $2, %%ecx\n\t"
" rep movsl\n\t"
/* Adjust the stack pointer to point into the new linuxBIOS image */
" addl 20(%%esp), %%esp\n\t"
/* Adjust the instruction pointer to point into the new linuxBIOS image */
" movl $1f, %%eax\n\t"
" addl 20(%%esp), %%eax\n\t"
" jmp *%%eax\n\t"
"1: \n\t"
/* Copy the linuxBIOS bounce buffer over linuxBIOS */
/* Move ``longs'' the linuxBIOS size is 4 byte aligned */
" movl 16(%%esp), %%edi\n\t"
" movl 12(%%esp), %%esi\n\t"
" movl 8(%%esp), %%ecx\n\t"
" shrl $2, %%ecx\n\t"
" rep movsl\n\t"
/* Now jump to the loaded image */
" movl $0x0E1FB007, %%eax\n\t"
" movl 0(%%esp), %%ebx\n\t"
" call *4(%%esp)\n\t"
/* The loaded image returned? */
" cli \n\t"
" cld \n\t"
/* Copy the saved copy of linuxBIOS where linuxBIOS runs */
/* Move ``longs'' the linuxBIOS size is 4 byte aligned */
" movl 16(%%esp), %%edi\n\t"
" movl 12(%%esp), %%esi\n\t"
" addl 8(%%esp), %%esi\n\t"
" movl 8(%%esp), %%ecx\n\t"
" shrl $2, %%ecx\n\t"
" rep movsl\n\t"
/* Adjust the stack pointer to point into the old linuxBIOS image */
" subl 20(%%esp), %%esp\n\t"
/* Adjust the instruction pointer to point into the old linuxBIOS image */
" movl $1f, %%eax\n\t"
" subl 20(%%esp), %%eax\n\t"
" jmp *%%eax\n\t"
"1: \n\t"
/* Drop the parameters I was passed */
" addl $24, %%esp\n\t"
/* Restore the callee save registers */
" popl %%ebx\n\t"
" popl %%edi\n\t"
" popl %%esi\n\t"
::
"g" (lb_start), "g" (buffer), "g" (lb_size),
"g" (entry), "g"(adjusted_boot_notes)
);
}

View File

@ -0,0 +1,281 @@
#include <console/console.h>
#include <mem.h>
#include <ip_checksum.h>
#include <boot/linuxbios_tables.h>
#include "linuxbios_table.h"
#include <string.h>
#include <version.h>
struct lb_header *lb_table_init(unsigned long addr)
{
struct lb_header *header;
/* 16 byte align the address */
addr += 15;
addr &= ~15;
header = (void *)addr;
header->signature[0] = 'L';
header->signature[1] = 'B';
header->signature[2] = 'I';
header->signature[3] = 'O';
header->header_bytes = sizeof(*header);
header->header_checksum = 0;
header->table_bytes = 0;
header->table_checksum = 0;
header->table_entries = 0;
return header;
}
struct lb_record *lb_first_record(struct lb_header *header)
{
struct lb_record *rec;
rec = (void *)(((char *)header) + sizeof(*header));
return rec;
}
struct lb_record *lb_last_record(struct lb_header *header)
{
struct lb_record *rec;
rec = (void *)(((char *)header) + sizeof(*header) + header->table_bytes);
return rec;
}
struct lb_record *lb_next_record(struct lb_record *rec)
{
rec = (void *)(((char *)rec) + rec->size);
return rec;
}
struct lb_record *lb_new_record(struct lb_header *header)
{
struct lb_record *rec;
rec = lb_last_record(header);
if (header->table_entries) {
header->table_bytes += rec->size;
}
rec = lb_last_record(header);
header->table_entries++;
rec->tag = LB_TAG_UNUSED;
rec->size = sizeof(*rec);
return rec;
}
struct lb_memory *lb_memory(struct lb_header *header)
{
struct lb_record *rec;
struct lb_memory *mem;
rec = lb_new_record(header);
mem = (struct lb_memory *)rec;
mem->tag = LB_TAG_MEMORY;
mem->size = sizeof(*mem);
return mem;
}
struct lb_mainboard *lb_mainboard(struct lb_header *header)
{
struct lb_record *rec;
struct lb_mainboard *mainboard;
rec = lb_new_record(header);
mainboard = (struct lb_mainboard *)rec;
mainboard->tag = LB_TAG_MAINBOARD;
mainboard->size = (sizeof(*mainboard) +
strlen(mainboard_vendor) + 1 +
strlen(mainboard_part_number) + 1 +
3) & ~3;
mainboard->vendor_idx = 0;
mainboard->part_number_idx = strlen(mainboard_vendor) + 1;
memcpy(mainboard->strings + mainboard->vendor_idx,
mainboard_vendor, strlen(mainboard_vendor) + 1);
memcpy(mainboard->strings + mainboard->part_number_idx,
mainboard_part_number, strlen(mainboard_part_number) + 1);
return mainboard;
}
void lb_strings(struct lb_header *header)
{
static const struct {
uint32_t tag;
const uint8_t *string;
} strings[] = {
{ LB_TAG_VERSION, linuxbios_version, },
{ LB_TAG_EXTRA_VERSION, linuxbios_extra_version, },
{ LB_TAG_BUILD, linuxbios_build, },
{ LB_TAG_COMPILE_TIME, linuxbios_compile_time, },
{ LB_TAG_COMPILE_BY, linuxbios_compile_by, },
{ LB_TAG_COMPILE_HOST, linuxbios_compile_host, },
{ LB_TAG_COMPILE_DOMAIN, linuxbios_compile_domain, },
{ LB_TAG_COMPILER, linuxbios_compiler, },
{ LB_TAG_LINKER, linuxbios_linker, },
{ LB_TAG_ASSEMBLER, linuxbios_assembler, },
};
int i;
for(i = 0; i < sizeof(strings)/sizeof(strings[0]); i++) {
struct lb_string *rec;
size_t len;
rec = (struct lb_string *)lb_new_record(header);
len = strlen(strings[i].string);
rec->tag = strings[i].tag;
rec->size = (sizeof(*rec) + len + 1 + 3) & ~3;
memcpy(rec->string, strings[i].string, len+1);
}
}
/* Some version of gcc have problems with 64 bit types so
* take an unsigned long instead of a uint64_t for now.
*/
void lb_memory_range(struct lb_memory *mem,
uint32_t type, unsigned long start, unsigned long size)
{
int entries;
entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
mem->map[entries].start = start;
mem->map[entries].size = size;
mem->map[entries].type = type;
mem->size += sizeof(mem->map[0]);
}
static void lb_memory_rangek(struct lb_memory *mem,
uint32_t type, unsigned long startk, unsigned long endk)
{
int entries;
entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
mem->map[entries].start = startk;
mem->map[entries].start <<= 10;
mem->map[entries].size = endk - startk;
mem->map[entries].size <<= 10;
mem->map[entries].type = type;
mem->size += sizeof(mem->map[0]);
}
static void lb_reserve_table_memory(struct lb_header *head)
{
struct lb_record *last_rec;
struct lb_memory *mem;
uint64_t start;
uint64_t end;
int i, entries;
last_rec = lb_last_record(head);
mem = get_lb_mem();
start = (unsigned long)head;
end = (unsigned long)last_rec;
entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
/* Resize the right two memory areas so this table is in
* a reserved area of memory. Everything has been carefully
* setup so that is all we need to do.
*/
for(i = 0; i < entries; i++ ) {
uint64_t map_start = mem->map[i].start;
uint64_t map_end = map_start + mem->map[i].size;
/* Does this area need to be expanded? */
if (map_end == start) {
mem->map[i].size = end - map_start;
}
/* Does this area need to be contracted? */
else if (map_start == start) {
mem->map[i].start = end;
mem->map[i].size = map_end - end;
}
}
}
unsigned long lb_table_fini(struct lb_header *head)
{
struct lb_record *rec, *first_rec;
rec = lb_last_record(head);
if (head->table_entries) {
head->table_bytes += rec->size;
}
lb_reserve_table_memory(head);
first_rec = lb_first_record(head);
head->table_checksum = compute_ip_checksum(first_rec, head->table_bytes);
head->header_checksum = 0;
head->header_checksum = compute_ip_checksum(head, sizeof(*head));
printk_debug("Wrote linuxbios table at: %p - %p checksum %lx\n",
head, rec, head->table_checksum);
return (unsigned long)rec;
}
/* Routines to extract part so the linuxBIOS table or
* information from the linuxBIOS table after we have written it.
* Currently get_lb_mem relies on a global we can change the
* implementaiton.
*/
static struct lb_memory *mem_ranges = 0;
struct lb_memory *get_lb_mem(void)
{
return mem_ranges;
}
unsigned long write_linuxbios_table(
unsigned long *processor_map,
struct mem_range *ram,
unsigned long low_table_start, unsigned long low_table_end,
unsigned long rom_table_startk, unsigned long rom_table_endk)
{
unsigned long table_size;
struct mem_range *ramp;
struct lb_header *head;
struct lb_memory *mem;
struct lb_record *rec_dest, *rec_src;
head = lb_table_init(low_table_end);
low_table_end = (unsigned long)head;
#if HAVE_OPTION_TABLE == 1
/* Write the option config table... */
rec_dest = lb_new_record(head);
rec_src = (struct lb_record *)&option_table;
memcpy(rec_dest, rec_src, rec_src->size);
#endif
mem = lb_memory(head);
mem_ranges = mem;
/* I assume there is always ram at address 0 */
/* Reserve our tables in low memory */
table_size = (low_table_end - low_table_start);
lb_memory_range(mem, LB_MEM_TABLE, 0, table_size);
lb_memory_range(mem, LB_MEM_RAM, table_size, (ram[0].sizek << 10) - table_size);
/* Reserving pci memory mapped space will keep the kernel from booting seeing
* any pci resources.
*/
for(ramp = &ram[1]; ramp->sizek; ramp++) {
unsigned long startk, endk;
startk = ramp->basek;
endk = startk + ramp->sizek;
if ((startk < rom_table_startk) && (endk > rom_table_startk)) {
lb_memory_rangek(mem, LB_MEM_RAM, startk, rom_table_startk);
startk = rom_table_startk;
}
if ((startk == rom_table_startk) && (endk > startk)) {
unsigned long tend;
tend = rom_table_endk;
if (tend > endk) {
tend = endk;
}
lb_memory_rangek(mem, LB_MEM_TABLE, rom_table_startk, tend);
startk = tend;
}
if (endk > startk) {
lb_memory_rangek(mem, LB_MEM_RAM, startk, endk);
}
}
/* Record our motheboard */
lb_mainboard(head);
/* Record our various random string information */
lb_strings(head);
low_table_end = lb_table_fini(head);
/* Remember where my valid memory ranges are */
return low_table_end;
}

View File

@ -0,0 +1,33 @@
#ifndef LINUXBIOS_TABLE_H
#define LINUXBIOS_TABLE_H
#include <boot/linuxbios_tables.h>
struct mem_range;
/* This file holds function prototypes for building the linuxbios table. */
unsigned long write_linuxbios_table(
unsigned long *processor_map,
struct mem_range *ram,
unsigned long low_table_start, unsigned long low_table_end,
unsigned long rom_table_start, unsigned long rom_table_end);
struct lb_header *lb_table_init(unsigned long addr);
struct lb_record *lb_first_record(struct lb_header *header);
struct lb_record *lb_last_record(struct lb_header *header);
struct lb_record *lb_next_record(struct lb_record *rec);
struct lb_record *lb_new_record(struct lb_header *header);
struct lb_memory *lb_memory(struct lb_header *header);
void lb_memory_range(struct lb_memory *mem,
uint32_t type, unsigned long startk, unsigned long sizek);
struct lb_mainboard *lb_mainboard(struct lb_header *header);
unsigned long lb_table_fini(struct lb_header *header);
/* Routines to extract part so the linuxBIOS table or information
* from the linuxBIOS table.
*/
struct lb_memory *get_lb_mem(void);
extern struct cmos_option_table option_table;
#endif /* LINUXBIOS_TABLE_H */

View File

@ -0,0 +1,93 @@
#include <console/console.h>
#include <arch/pirq_routing.h>
#include <string.h>
#ifdef DEBUG
void check_pirq_routing_table(void)
{
const u8 *addr;
const struct irq_routing_table *rt;
int i;
u8 sum;
printk_info("Checking IRQ routing tables...\n");
#ifdef(IRQ_SLOT_COUNT)
if (sizeof(intel_irq_routing_table) != intel_irq_routing_table.size) {
printk_warning("Inconsistent IRQ routing table size\n");
}
#endif
rt = &intel_irq_routing_table;
addr = (u8 *)rt;
sum = 0;
for (i = 0; i < rt->size; i++)
sum += addr[i];
printk_debug("%s:%6d:%s() - irq_routing_table located at: 0x%p\n",
__FILE__, __LINE__, __FUNCTION__, addr);
sum = (unsigned char)(rt->checksum-sum);
if (sum != rt->checksum) {
printk_warning("%s:%6d:%s() - "
"checksum is: 0x%02x but should be: 0x%02x\n",
__FILE__, __LINE__, __FUNCTION__, rt->checksum, sum);
}
if (rt->signature != PIRQ_SIGNATURE || rt->version != PIRQ_VERSION ||
rt->size % 16 || rt->size < sizeof(struct irq_routing_table)) {
printk_warning("%s:%6d:%s() - "
"Interrupt Routing Table not valid\n",
__FILE__, __LINE__, __FUNCTION__);
return;
}
sum = 0;
for (i=0; i<rt->size; i++)
sum += addr[i];
if (sum) {
printk_warning("%s:%6d:%s() - "
"checksum error in irq routing table\n",
__FILE__, __LINE__, __FUNCTION__);
}
printk_info("done.\n");
}
int verify_copy_pirq_routing_table(unsigned long addr)
{
int i;
u8 *rt_orig, *rt_curr;
rt_curr = (u8*)addr;
rt_orig = (u8*)&intel_irq_routing_table;
printk_info("Verifing priq routing tables copy at 0x%x...", addr);
for (i = 0; i < intel_irq_routing_table.size; i++) {
if (*(rt_curr + i) != *(rt_orig + i)) {
printk_info("failed\n");
return -1;
}
}
printk_info("succeed\n");
return 0;
}
#else
#define verify_copy_pirq_routing_table(addr)
#endif
unsigned long copy_pirq_routing_table(unsigned long addr)
{
/* Align the table to be 16 byte aligned. */
addr += 15;
addr &= ~15;
/* This table must be betweeen 0xf0000 & 0x100000 */
printk_info("Copying IRQ routing tables to 0x%x...", addr);
memcpy((void *)addr, &intel_irq_routing_table, intel_irq_routing_table.size);
printk_info("done.\n");
verify_copy_pirq_routing_table(addr);
return addr + intel_irq_routing_table.size;
}

View File

@ -0,0 +1,69 @@
#include <console/console.h>
#include <mem.h>
#include <cpu/cpu.h>
#include <boot/tables.h>
#include <boot/linuxbios_tables.h>
#include <arch/pirq_routing.h>
#include <arch/smp/mpspec.h>
#include "linuxbios_table.h"
#if CONFIG_SMP && CONFIG_MAX_PHYSICAL_CPUS && (CONFIG_MAX_PHYSICAL_CPUS < CONFIG_MAX_CPUS)
static void remove_logical_cpus(unsigned long *processor_map)
{
/* To turn off hyperthreading just remove the logical
* cpus from the processor map.
*/
int disable_logical_cpus = !CONFIG_LOGICAL_CPUS;
if (get_option(&disable_logical_cpus,"hyper_threading")) {
disable_logical_cpus = !CONFIG_LOGICAL_CPUS;
}
if (disable_logical_cpus) {
/* disable logical cpus */
int cnt;
for(cnt=MAX_PHYSICAL_CPUS;cnt<MAX_CPUS;cnt++)
processor_map[cnt]=0;
printk_debug("logical cpus disabled\n");
}
}
#else
#define remove_logical_cpus(processor_map) do {} while(0)
#endif /* CONFIG_SMP && CONFIG_MAX_PHYSICAL_CPUS */
struct lb_memory *write_tables(struct mem_range *mem, unsigned long *processor_map)
{
unsigned long low_table_start, low_table_end;
unsigned long rom_table_start, rom_table_end;
rom_table_start = 0xf0000;
rom_table_end = 0xf0000;
/* Start low addr at 16 bytes instead of 0 because of a buglet
* in the generic linux unzip code, as it tests for the a20 line.
*/
low_table_start = 0;
low_table_end = 16;
post_code(0x9a);
check_pirq_routing_table();
/* This table must be betweeen 0xf0000 & 0x100000 */
rom_table_end = copy_pirq_routing_table(rom_table_end);
rom_table_end = (rom_table_end + 1023) & ~1023;
/* copy the smp block to address 0 */
post_code(0x96);
/* The smp table must be in 0-1K, 639K-640K, or 960K-1M */
remove_logical_cpus(processor_map);
low_table_end = write_smp_table(low_table_end, processor_map);
/* Don't write anything in the traditional x86 BIOS data segment */
if (low_table_end < 0x500) {
low_table_end = 0x500;
}
/* The linuxbios table must be in 0-4K or 960K-1M */
write_linuxbios_table(processor_map, mem,
low_table_start, low_table_end,
rom_table_start >> 10, rom_table_end >> 10);
return get_lb_mem();
}

View File

@ -0,0 +1,30 @@
#ifndef ASM_H
#define ASM_H
#define ASSEMBLER
/*
* Bootstrap code for the STPC Consumer
* Copyright (c) 1999 by Net Insight AB. All Rights Reserved.
*
* $Id$
*
*/
#define I386_ALIGN_TEXT 0
#define I386_ALIGN_DATA 0
/*
* XXX
*/
#ifdef __ELF__
#define EXT(x) x
#else
#define EXT(x) _ ## x
#endif
#define STATIC(x) .align I386_ALIGN_TEXT; EXT(x):
#define GLOBAL(x) .globl EXT(x); STATIC(x)
#define ENTRY(x) .text; GLOBAL(x)
#endif /* ASM_H */

View File

@ -0,0 +1,8 @@
#ifndef ASM_I386_BOOT_H
#define ASM_I386_BOOT_H
#define ELF_CLASS ELFCLASS32
#define ELF_DATA ELFDATA2LSB
#define ELF_ARCH EM_386
#endif /* ASM_I386_BOOT_H */

View File

@ -0,0 +1,369 @@
/*
This software and ancillary information (herein called SOFTWARE )
called LinuxBIOS is made available under the terms described
here. The SOFTWARE has been approved for release with associated
LA-CC Number 00-34 . Unless otherwise indicated, this SOFTWARE has
been authored by an employee or employees of the University of
California, operator of the Los Alamos National Laboratory under
Contract No. W-7405-ENG-36 with the U.S. Department of Energy. The
U.S. Government has rights to use, reproduce, and distribute this
SOFTWARE. The public may copy, distribute, prepare derivative works
and publicly display this SOFTWARE without charge, provided that this
Notice and any statement of authorship are reproduced on all copies.
Neither the Government nor the University makes any warranty, express
or implied, or assumes any liability or responsibility for the use of
this SOFTWARE. If SOFTWARE is modified to produce derivative works,
such modified SOFTWARE should be clearly marked, so as not to confuse
it with the version available from LANL.
*/
/* Copyright 2000, Ron Minnich, Advanced Computing Lab, LANL
* rminnich@lanl.gov
*/
#ifndef ROM_INTEL_H
#define ROM_INTEL_H
/*
* Bootstrap code for the Intel
*
* $Id$
*
*/
/*
* Config registers.
*/
/* yeah, yeah, I know these are macros, which is bad. Don't forget:
* we have almost no assembly, so I am not worrying just yet about this.
* we'll fix it someday if we care. My guess is we won't.
*/
/* well we want functions. But first we want to see it work at all. */
#undef FUNCTIONS
#ifndef FUNCTIONS
#define RET_LABEL(label) \
jmp label##_done
#define CALL_LABEL(label) \
jmp label ;\
label##_done:
#define CALLSP(func) \
lea 0f, %esp ; \
jmp func ; \
0:
#define RETSP \
jmp *%esp
#define DELAY(x) mov x, %ecx ;\
1: loop 1b ;\
/*
* Macro: PCI_WRITE_CONFIG_BYTE
* Arguments: %eax address to write to (includes bus, device, function, &offset)
* %dl byte to write
*
* Results: none
*
* Trashed: %eax, %edx
* Effects: writes a single byte to pci config space
*
* Notes: This routine is optimized for minimal register usage.
* And the tricks it does cannot scale beyond writing a single byte.
*
* What it does is almost simple.
* It preserves %eax (baring special bits) until it is written
* out to the appropriate port. And hides the data byte
* in the high half of edx.
*
* In %edx[3] it stores the byte to write.
* In %edx[2] it stores the lower three bits of the address.
*/
#define PCI_WRITE_CONFIG_BYTE \
shll $8, %edx ; \
movb %al, %dl ; \
andb $0x3, %dl ; \
shll $16, %edx ; \
\
orl $0x80000000, %eax ; \
andl $0xfffffffc, %eax ; \
movw $0xcf8, %dx ; \
outl %eax, %dx ; \
\
shrl $16, %edx ; \
movb %dh, %al ; \
movb $0, %dh ; \
addl $0xcfc, %edx ; \
outb %al, %dx
/*
* Macro: PCI_WRITE_CONFIG_WORD
* Arguments: %eax address to write to (includes bus, device, function, &offset)
* %ecx word to write
*
* Results: none
*
* Trashed: %eax, %edx
* Preserved: %ecx
* Effects: writes a single byte to pci config space
*
* Notes: This routine is optimized for minimal register usage.
*
* What it does is almost simple.
* It preserves %eax (baring special bits) until it is written
* out to the appropriate port. And hides the least significant
* bits of the address in the high half of edx.
*
* In %edx[2] it stores the lower three bits of the address.
*/
#define PCI_WRITE_CONFIG_WORD \
movb %al, %dl ; \
andl $0x3, %edx ; \
shll $16, %edx ; \
\
orl $0x80000000, %eax ; \
andl $0xfffffffc, %eax ; \
movw $0xcf8, %dx ; \
outl %eax, %dx ; \
\
shrl $16, %edx ; \
movl %ecx, %eax ; \
addl $0xcfc, %edx ; \
outw %ax, %dx
/*
* Macro: PCI_WRITE_CONFIG_DWORD
* Arguments: %eax address to write to (includes bus, device, function, &offset)
* %ecx dword to write
*
* Results: none
*
* Trashed: %eax, %edx
* Preserved: %ecx
* Effects: writes a single byte to pci config space
*
* Notes: This routine is optimized for minimal register usage.
*
* What it does is almost simple.
* It preserves %eax (baring special bits) until it is written
* out to the appropriate port. And hides the least significant
* bits of the address in the high half of edx.
*
* In %edx[2] it stores the lower three bits of the address.
*/
#define PCI_WRITE_CONFIG_DWORD \
movb %al, %dl ; \
andl $0x3, %edx ; \
shll $16, %edx ; \
\
orl $0x80000000, %eax ; \
andl $0xfffffffc, %eax ; \
movw $0xcf8, %dx ; \
outl %eax, %dx ; \
\
shrl $16, %edx ; \
movl %ecx, %eax ; \
addl $0xcfc, %edx ; \
outl %eax, %dx
/*
* Macro: PCI_READ_CONFIG_BYTE
* Arguments: %eax address to read from (includes bus, device, function, &offset)
*
* Results: %al Byte read
*
* Trashed: %eax, %edx
* Effects: reads a single byte from pci config space
*
* Notes: This routine is optimized for minimal register usage.
*
* What it does is almost simple.
* It preserves %eax (baring special bits) until it is written
* out to the appropriate port. And hides the least significant
* bits of the address in the high half of edx.
*
* In %edx[2] it stores the lower three bits of the address.
*/
#define PCI_READ_CONFIG_BYTE \
movb %al, %dl ; \
andl $0x3, %edx ; \
shll $16, %edx ; \
\
orl $0x80000000, %eax ; \
andl $0xfffffffc, %eax ; \
movw $0xcf8, %dx ; \
outl %eax, %dx ; \
\
shrl $16, %edx ; \
addl $0xcfc, %edx ; \
inb %dx, %al
/*
* Macro: PCI_READ_CONFIG_WORD
* Arguments: %eax address to read from (includes bus, device, function, &offset)
*
* Results: %ax word read
*
* Trashed: %eax, %edx
* Effects: reads a 2 bytes from pci config space
*
* Notes: This routine is optimized for minimal register usage.
*
* What it does is almost simple.
* It preserves %eax (baring special bits) until it is written
* out to the appropriate port. And hides the least significant
* bits of the address in the high half of edx.
*
* In %edx[2] it stores the lower three bits of the address.
*/
#define PCI_READ_CONFIG_WORD \
movb %al, %dl ; \
andl $0x3, %edx ; \
shll $16, %edx ; \
\
orl $0x80000000, %eax ; \
andl $0xfffffffc, %eax ; \
movw $0xcf8, %dx ; \
outl %eax, %dx ; \
\
shrl $16, %edx ; \
addl $0xcfc, %edx ; \
inw %dx, %ax
/*
* Macro: PCI_READ_CONFIG_DWORD
* Arguments: %eax address to read from (includes bus, device, function, &offset)
*
* Results: %eax
*
* Trashed: %edx
* Effects: reads 4 bytes from pci config space
*
* Notes: This routine is optimized for minimal register usage.
*
* What it does is almost simple.
* It preserves %eax (baring special bits) until it is written
* out to the appropriate port. And hides the least significant
* bits of the address in the high half of edx.
*
* In %edx[2] it stores the lower three bits of the address.
*/
#define PCI_READ_CONFIG_DWORD \
movb %al, %dl ; \
andl $0x3, %edx ; \
shll $16, %edx ; \
\
orl $0x80000000, %eax ; \
andl $0xfffffffc, %eax ; \
movw $0xcf8, %dx ; \
outl %eax, %dx ; \
\
shrl $16, %edx ; \
addl $0xcfc, %edx ; \
inl %dx, %eax
#define CS_READ(which) \
mov $0x80000000,%eax ; \
mov which,%ax ; \
and $0xfc,%al /* clear bits 1-0 */ ; \
mov $0xcf8,%dx /* port 0xcf8 ?*/ ; \
outl %eax,%dx /* open up CS config */ ; \
add $0x4,%dl /* 0xcfc data port 0 */ ; \
mov which,%al ; \
and $0x3,%al /* only bits 1-0 */ ; \
add %al,%dl ; \
inb %dx,%al /* read */ ; \
#define CS_WRITE(which, data) \
mov $0x80000000,%eax /* 32bit word with bit 31 set */ ; \
mov which,%ax /* put the reg# in the low part */ ; \
and $0xfc,%al /* dword align the reg# */ ; \
mov $0xcf8,%dx /* enable port */ ; \
outl %eax,%dx ; \
add $0x4,%dl /* 1st data port */ ; \
mov which,%ax /* register# */ ; \
and $0x3,%ax ; \
add %al,%dl ; \
mov data, %al ; \
outb %al,%dx /* write to reg */
#define REGBIS(which, bis) \
CS_READ(which) ;\
movb bis, %cl ;\
orb %al, %cl ;\
CS_WRITE(which, %cl)
#define REGBIC(which, bic) \
CS_READ(which) ;\
movb bic, %cl ;\
notb %cl ;\
andb %al, %cl ;\
CS_WRITE(which, %cl)
/* macro to BIC and BIS a reg. calls read a reg,
* does a BIC and then a BIS on it.
* to clear no bits, make BIC 0.
* to set no bits, make BIS 0
*/
#define REGBICBIS(which, bic, bis) \
CS_READ(which) ;\
movb bic, %cl ;\
notb %cl ;\
andb %cl, %al ;\
movb bis, %cl ;\
orb %al, %cl ;\
CS_WRITE(which, %cl)
#else
NO FUNCTIONS YET!
#endif
/* originally this macro was from STPC BIOS */
#define intel_chip_post_macro(value) \
movb $value, %al ; \
outb %al, $0x80
#define INTEL_PDATA_MAGIC 0xdeadbeef
/* SLOW_DOWN_IO is a delay we can use that is roughly cpu neutral,
* and can be used before memory or timer chips come up.
* Since this hits the isa bus it's roughly
*/
#define SLOW_DOWN_IO inb $0x80, %al
#endif /* ROM_INTEL_H */

View File

@ -0,0 +1,76 @@
#ifndef _ASM_IO_H
#define _ASM_IO_H
/*
* This file contains the definitions for the x86 IO instructions
* inb/inw/inl/outb/outw/outl and the "string versions" of the same
* (insb/insw/insl/outsb/outsw/outsl).
*
* This file is not meant to be obfuscating: it's just complicated
* to (a) handle it all in a way that makes gcc able to optimize it
* as well as possible and (b) trying to avoid writing the same thing
* over and over again with slight variations and possibly making a
* mistake somewhere.
*/
/*
* Bit simplified and optimized by Jan Hubicka
* Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999.
*/
/*
* Talk about misusing macros..
*/
#define __OUT1(s,x) \
extern inline void out##s(unsigned x value, unsigned short port) {
#define __OUT2(s,s1,s2) \
__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
#define __OUT(s,s1,x) \
__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); }
#define __IN1(s) \
extern inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
#define __IN2(s,s1,s2) \
__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
#define __IN(s,s1,i...) \
__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; }
#define __INS(s) \
extern inline void ins##s(unsigned short port, void * addr, unsigned long count) \
{ __asm__ __volatile__ ("cld ; rep ; ins" #s \
: "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
#define __OUTS(s) \
extern inline void outs##s(unsigned short port, const void * addr, unsigned long count) \
{ __asm__ __volatile__ ("cld ; rep ; outs" #s \
: "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
#define RETURN_TYPE unsigned char
__IN(b,"")
#undef RETURN_TYPE
#define RETURN_TYPE unsigned short
__IN(w,"")
#undef RETURN_TYPE
#define RETURN_TYPE unsigned int
__IN(l,"")
#undef RETURN_TYPE
__OUT(b,"b",char)
__OUT(w,"w",short)
__OUT(l,,int)
__INS(b)
__INS(w)
__INS(l)
__OUTS(b)
__OUTS(w)
__OUTS(l)
#endif

View File

@ -0,0 +1,9 @@
#ifndef PCI_CONF_REG_INDEX
// These are defined in the PCI spec, and hence are theoretically
// inclusive of ANYTHING that uses a PCI bus.
#define PCI_CONF_REG_INDEX 0xcf8
#define PCI_CONF_REG_DATA 0xcfc
#define CONFIG_ADDR(bus,devfn,where) (((bus) << 16) | ((devfn) << 8) | (where))
#endif

View File

@ -0,0 +1,54 @@
#ifndef ARCH_PIRQ_ROUTING_H
#define ARCH_PIRQ_ROUTING_H
#include <stdint.h>
#define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24))
#define PIRQ_VERSION 0x0100
struct irq_info {
uint8_t bus, devfn; /* Bus, device and function */
struct {
uint8_t link; /* IRQ line ID, chipset dependent, 0=not routed */
uint16_t bitmap; /* Available IRQs */
} __attribute__((packed)) irq[4];
uint8_t slot; /* Slot number, 0=onboard */
uint8_t rfu;
} __attribute__((packed));
#if defined(IRQ_SLOT_COUNT)
#define IRQ_SLOTS_COUNT IRQ_SLOT_COUNT
#elif (__GNUC__ < 3)
#define IRQ_SLOTS_COUNT 1
#else
#define IRQ_SLOTS_COUNT
#endif
struct irq_routing_table {
uint32_t signature; /* PIRQ_SIGNATURE should be here */
uint16_t version; /* PIRQ_VERSION */
uint16_t size; /* Table size in bytes */
uint8_t rtr_bus, rtr_devfn; /* Where the interrupt router lies */
uint16_t exclusive_irqs; /* IRQs devoted exclusively to PCI usage */
uint16_t rtr_vendor, rtr_device; /* Vendor and device ID of interrupt router */
uint32_t miniport_data; /* Crap */
uint8_t rfu[11];
uint8_t checksum; /* Modulo 256 checksum must give zero */
struct irq_info slots[IRQ_SLOTS_COUNT];
} __attribute__((packed));
extern const struct irq_routing_table intel_irq_routing_table;
#if defined(DEBUG) && defined(HAVE_PIRQ_TABLE)
void check_pirq_routing_table(void);
#else
#define check_pirq_routing_table() do {} while(0)
#endif
#if defined(HAVE_PIRQ_TABLE)
unsigned long copy_pirq_routing_table(unsigned long start);
#else
#define copy_pirq_routing_table(start) (start)
#endif
#endif /* ARCH_PIRQ_ROUTING_H */

View File

@ -0,0 +1,10 @@
#ifndef ROM_SEGS_H
#define ROM_SEGS_H
#define ROM_CODE_SEG 0x08
#define ROM_DATA_SEG 0x10
#define CACHE_RAM_CODE_SEG 0x18
#define CACHE_RAM_DATA_SEG 0x20
#endif /* ROM_SEGS_H */

View File

@ -0,0 +1,84 @@
static void outb(unsigned char value, unsigned short port)
{
__builtin_outb(value, port);
}
static void outw(unsigned short value, unsigned short port)
{
__builtin_outw(value, port);
}
static void outl(unsigned int value, unsigned short port)
{
__builtin_outl(value, port);
}
static unsigned char inb(unsigned short port)
{
return __builtin_inb(port);
}
static unsigned char inw(unsigned short port)
{
return __builtin_inw(port);
}
static unsigned char inl(unsigned short port)
{
return __builtin_inl(port);
}
static void hlt(void)
{
__builtin_hlt();
}
static unsigned int config_cmd(unsigned char bus, unsigned devfn, unsigned where)
{
return 0x80000000 | (bus << 16) | (devfn << 8) | (where & ~3);
}
static unsigned char pcibios_read_config_byte(
unsigned char bus, unsigned devfn, unsigned where)
{
outl(config_cmd(bus, devfn, where), 0xCF8);
return inb(0xCFC + (where & 3));
}
static unsigned short pcibios_read_config_word(
unsigned char bus, unsigned devfn, unsigned where)
{
outl(config_cmd(bus, devfn, where), 0xCF8);
return inw(0xCFC + (where & 2));
}
static unsigned int pcibios_read_config_dword(
unsigned char bus, unsigned devfn, unsigned where)
{
outl(config_cmd(bus, devfn, where), 0xCF8);
return inl(0xCFC);
}
static void pcibios_write_config_byte(
unsigned char bus, unsigned devfn, unsigned where, unsigned char value)
{
outl(config_cmd(bus, devfn, where), 0xCF8);
outb(value, 0xCFC + (where & 3));
}
static void pcibios_write_config_word(
unsigned char bus, unsigned devfn, unsigned where, unsigned short value)
{
outl(config_cmd(bus, devfn, where), 0xCF8);
outw(value, 0xCFC + (where & 2));
}
static void pcibios_write_config_dword(
unsigned char bus, unsigned devfn, unsigned where, unsigned int value)
{
outl(config_cmd(bus, devfn, where), 0xCF8);
outl(value, 0xCFC);
}

View File

@ -0,0 +1,282 @@
#ifndef __ASM_MPSPEC_H
#define __ASM_MPSPEC_H
#ifdef HAVE_MP_TABLE
/*
* Structure definitions for SMP machines following the
* Intel Multiprocessing Specification 1.1 and 1.4.
*/
/*
* This tag identifies where the SMP configuration
* information is.
*/
#define SMP_MAGIC_IDENT (('_'<<24)|('P'<<16)|('M'<<8)|'_')
/*
* a maximum of 16 APICs with the current APIC ID architecture.
*/
#define MAX_APICS 16
#define SMP_FLOATING_TABLE_LEN sizeof(struct intel_mp_floating)
struct intel_mp_floating
{
char mpf_signature[4]; /* "_MP_" */
unsigned long mpf_physptr; /* Configuration table address */
unsigned char mpf_length; /* Our length (paragraphs) */
unsigned char mpf_specification;/* Specification version */
unsigned char mpf_checksum; /* Checksum (makes sum 0) */
unsigned char mpf_feature1; /* Standard or configuration ? */
unsigned char mpf_feature2; /* Bit7 set for IMCR|PIC */
unsigned char mpf_feature3; /* Unused (0) */
unsigned char mpf_feature4; /* Unused (0) */
unsigned char mpf_feature5; /* Unused (0) */
};
struct mp_config_table
{
char mpc_signature[4];
#define MPC_SIGNATURE "PCMP"
unsigned short mpc_length; /* Size of table */
char mpc_spec; /* 0x01 */
char mpc_checksum;
char mpc_oem[8];
char mpc_productid[12];
unsigned long mpc_oemptr; /* 0 if not present */
unsigned short mpc_oemsize; /* 0 if not present */
unsigned short mpc_entry_count;
unsigned long mpc_lapic; /* APIC address */
unsigned short mpe_length; /* Extended Table size */
unsigned char mpe_checksum; /* Extended Table checksum */
unsigned char reserved;
};
/* Followed by entries */
#define MP_PROCESSOR 0
#define MP_BUS 1
#define MP_IOAPIC 2
#define MP_INTSRC 3
#define MP_LINTSRC 4
struct mpc_config_processor
{
unsigned char mpc_type;
unsigned char mpc_apicid; /* Local APIC number */
unsigned char mpc_apicver; /* Its versions */
unsigned char mpc_cpuflag;
#define MPC_CPU_ENABLED 1 /* Processor is available */
#define MPC_CPU_BOOTPROCESSOR 2 /* Processor is the BP */
unsigned long mpc_cpufeature;
#define MPC_CPU_STEPPING_MASK 0x0F
#define MPC_CPU_MODEL_MASK 0xF0
#define MPC_CPU_FAMILY_MASK 0xF00
unsigned long mpc_featureflag; /* CPUID feature value */
unsigned long mpc_reserved[2];
};
struct mpc_config_bus
{
unsigned char mpc_type;
unsigned char mpc_busid;
unsigned char mpc_bustype[6] __attribute((packed));
};
#define BUSTYPE_EISA "EISA"
#define BUSTYPE_ISA "ISA"
#define BUSTYPE_INTERN "INTERN" /* Internal BUS */
#define BUSTYPE_MCA "MCA"
#define BUSTYPE_VL "VL" /* Local bus */
#define BUSTYPE_PCI "PCI"
#define BUSTYPE_PCMCIA "PCMCIA"
struct mpc_config_ioapic
{
unsigned char mpc_type;
unsigned char mpc_apicid;
unsigned char mpc_apicver;
unsigned char mpc_flags;
#define MPC_APIC_USABLE 0x01
unsigned long mpc_apicaddr;
};
struct mpc_config_intsrc
{
unsigned char mpc_type;
unsigned char mpc_irqtype;
unsigned short mpc_irqflag;
unsigned char mpc_srcbus;
unsigned char mpc_srcbusirq;
unsigned char mpc_dstapic;
unsigned char mpc_dstirq;
};
enum mp_irq_source_types {
mp_INT = 0,
mp_NMI = 1,
mp_SMI = 2,
mp_ExtINT = 3
};
#define MP_IRQ_POLARITY_DEFAULT 0x0
#define MP_IRQ_POLARITY_HIGH 0x1
#define MP_IRQ_POLARITY_LOW 0x3
#define MP_IRQ_POLARITY_MASK 0x3
#define MP_IRQ_TRIGGER_DEFAULT 0x0
#define MP_IRQ_TRIGGER_EDGE 0x4
#define MP_IRQ_TRIGGER_LEVEL 0xc
#define MP_IRQ_TRIGGER_MASK 0xc
struct mpc_config_lintsrc
{
unsigned char mpc_type;
unsigned char mpc_irqtype;
unsigned short mpc_irqflag;
unsigned char mpc_srcbusid;
unsigned char mpc_srcbusirq;
unsigned char mpc_destapic;
#define MP_APIC_ALL 0xFF
unsigned char mpc_destapiclint;
};
/*
* Default configurations
*
* 1 2 CPU ISA 82489DX
* 2 2 CPU EISA 82489DX neither IRQ 0 timer nor IRQ 13 DMA chaining
* 3 2 CPU EISA 82489DX
* 4 2 CPU MCA 82489DX
* 5 2 CPU ISA+PCI
* 6 2 CPU EISA+PCI
* 7 2 CPU MCA+PCI
*/
#define MAX_IRQ_SOURCES 128
#define MAX_MP_BUSSES 32
enum mp_bustype {
MP_BUS_ISA,
MP_BUS_EISA,
MP_BUS_PCI,
MP_BUS_MCA
};
/* Followed by entries */
#define MPE_SYSTEM_ADDRESS_SPACE 0x80
#define MPE_BUS_HIERARCHY 0x81
#define MPE_COMPATIBILITY_ADDRESS_SPACE 0x82
struct mp_exten_config {
unsigned char mpe_type;
unsigned char mpe_length;
};
typedef struct mp_exten_config *mpe_t;
struct mp_exten_system_address_space {
unsigned char mpe_type;
unsigned char mpe_length;
unsigned char mpe_busid;
unsigned char mpe_address_type;
#define ADDRESS_TYPE_IO 0
#define ADDRESS_TYPE_MEM 1
#define ADDRESS_TYPE_PREFETCH 2
unsigned int mpe_address_base_low;
unsigned int mpe_address_base_high;
unsigned int mpe_address_length_low;
unsigned int mpe_address_length_high;
};
struct mp_exten_bus_hierarchy {
unsigned char mpe_type;
unsigned char mpe_length;
unsigned char mpe_busid;
unsigned char mpe_bus_info;
#define BUS_SUBTRACTIVE_DECODE 1
unsigned char mpe_parent_busid;
unsigned char reserved[3];
};
struct mp_exten_compatibility_address_space {
unsigned char mpe_type;
unsigned char mpe_length;
unsigned char mpe_busid;
unsigned char mpe_address_modifier;
#define ADDRESS_RANGE_SUBTRACT 1
#define ADDRESS_RANGE_ADD 0
unsigned int mpe_range_list;
#define RANGE_LIST_IO_ISA 0
/* X100 - X3FF
* X500 - X7FF
* X900 - XBFF
* XD00 - XFFF
*/
#define RANGE_LIST_IO_VGA 1
/* X3B0 - X3BB
* X3C0 - X3DF
* X7B0 - X7BB
* X7C0 - X7DF
* XBB0 - XBBB
* XBC0 - XBDF
* XFB0 - XFBB
* XFC0 - XCDF
*/
};
/* Default local apic addr */
#define LAPIC_ADDR 0xFEE00000
void *smp_next_mpc_entry(struct mp_config_table *mc);
void *smp_next_mpe_entry(struct mp_config_table *mc);
void smp_write_processor(struct mp_config_table *mc,
unsigned char apicid, unsigned char apicver,
unsigned char cpuflag, unsigned int cpufeature,
unsigned int featureflag);
void smp_write_processors(struct mp_config_table *mc,
unsigned long *processor_map);
void smp_write_bus(struct mp_config_table *mc,
unsigned char id, unsigned char *bustype);
void smp_write_ioapic(struct mp_config_table *mc,
unsigned char id, unsigned char ver,
unsigned long apicaddr);
void smp_write_intsrc(struct mp_config_table *mc,
unsigned char irqtype, unsigned short irqflag,
unsigned char srcbus, unsigned char srcbusirq,
unsigned char dstapic, unsigned char dstirq);
void smp_write_lintsrc(struct mp_config_table *mc,
unsigned char irqtype, unsigned short irqflag,
unsigned char srcbusid, unsigned char srcbusirq,
unsigned char destapic, unsigned char destapiclint);
void smp_write_address_space(struct mp_config_table *mc,
unsigned char busid, unsigned char address_type,
unsigned int address_base_low, unsigned int address_base_high,
unsigned int address_length_low, unsigned int address_length_high);
void smp_write_bus_hierarchy(struct mp_config_table *mc,
unsigned char busid, unsigned char bus_info,
unsigned char parent_busid);
void smp_write_compatibility_address_space(struct mp_config_table *mc,
unsigned char busid, unsigned char address_modifier,
unsigned int range_list);
unsigned char smp_compute_checksum(void *v, int len);
void *smp_write_floating_table(unsigned long addr);
unsigned long write_smp_table(unsigned long addr, unsigned long *processor_map);
/* A table (per mainboard) listing the initial apicid of each cpu. */
extern unsigned long initial_apicid[MAX_CPUS];
#else /* HAVE_MP_TABLE */
static inline
unsigned long write_smp_table(unsigned long addr, unsigned long *processor_map)
{
return addr;
}
#endif /* HAVE_MP_TABLE */
#endif

View File

@ -0,0 +1,20 @@
#ifndef I386_BITOPS_H
#define I386_BITOPS_H
/**
* log2 - Find the truncated log base 2 of x
*/
static inline unsigned long log2(unsigned long x)
{
unsigned long r = 0;
__asm__(
"bsrl %1, %0\n\t"
"jnz 1f\n\t"
"movl $-1, %0\n\t"
"1:\n\t"
: "=r" (r) : "r" (x));
return r;
}
#endif /* I386_BITOPS_H */

View File

@ -0,0 +1,15 @@
#ifndef I386_STDDEF_H
#define I386_STDDEF_H
typedef long ptrdiff_t;
typedef unsigned long size_t;
typedef long ssize_t;
typedef int wchar_t;
typedef unsigned int wint_t;
#define NULL 0
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif /* I386_STDDEF_H */

View File

@ -0,0 +1,52 @@
#ifndef I386_STDINT_H
#define I386_STDINT_H
/* Exact integral types */
typedef unsigned char uint8_t;
typedef signed char int8_t;
typedef unsigned short uint16_t;
typedef signed short int16_t;
typedef unsigned int uint32_t;
typedef signed int int32_t;
typedef unsigned long long uint64_t;
typedef signed long long int64_t;
/* Small types */
typedef unsigned char uint_least8_t;
typedef signed char int_least8_t;
typedef unsigned short uint_least16_t;
typedef signed short int_least16_t;
typedef unsigned int uint_least32_t;
typedef signed int int_least32_t;
typedef unsigned long long uint_least64_t;
typedef signed long long int_least64_t;
/* Fast Types */
typedef unsigned char uint_fast8_t;
typedef signed char int_fast8_t;
typedef unsigned int uint_fast16_t;
typedef signed int int_fast16_t;
typedef unsigned int uint_fast32_t;
typedef signed int int_fast32_t;
typedef unsigned long long uint_fast64_t;
typedef signed long long int_fast64_t;
/* Types for `void *' pointers. */
typedef int intptr_t;
typedef unsigned int uintptr_t;
/* Largest integral types */
typedef long long int intmax_t;
typedef unsigned long long uintmax_t;
#endif /* I386_STDINT_H */

135
src/arch/i386/lib/c_start.S Normal file
View File

@ -0,0 +1,135 @@
#include <arch/asm.h>
#include <arch/intel.h>
#ifdef SMP
#include <cpu/p6/apic.h>
#endif
.section ".text"
.code32
.globl _start
_start:
cli
lgdt %cs:gdtaddr
ljmp $0x10, $1f
1: movl $0x18, %eax
movl %eax, %ds
movl %eax, %es
movl %eax, %ss
movl %eax, %fs
movl %eax, %gs
intel_chip_post_macro(0x13) /* post 12 */
/** clear stack */
leal EXT(_stack), %edi
movl $EXT(_estack), %ecx
subl %edi, %ecx
xorl %eax, %eax
rep
stosb
/** clear bss */
leal EXT(_bss), %edi
movl $EXT(_ebss), %ecx
subl %edi, %ecx
jz .Lnobss
xorl %eax, %eax
rep
stosb
.Lnobss:
/* set new stack */
movl $_estack, %esp
#ifdef SMP
/* Get the cpu id */
movl $APIC_DEFAULT_BASE, %edi
movl APIC_ID(%edi), %eax
shrl $24, %eax
/* Get the cpu index (MAX_CPUS on error) */
movl $-4, %ebx
1: addl $4, %ebx
cmpl $(MAX_CPUS << 2), %ebx
je 2
cmpl %eax, EXT(initial_apicid)(%ebx)
jne 1b
2: shrl $2, %ebx
/* Now compute the appropriate stack */
movl %ebx, %eax
movl $STACK_SIZE, %ebx
mull %ebx
subl %eax, %esp
#endif
/* push the boot_complete flag */
pushl %ebp
/* Save the stack location */
movl %esp, %ebp
/*
* Now we are finished. Memory is up, data is copied and
* bss is cleared. Now we call the main routine and
* let it do the rest.
*/
intel_chip_post_macro(0xfe) /* post fe */
/* Resort the stack location */
movl %ebp, %esp
/* The boot_complete flag has already been pushed */
call EXT(hardwaremain)
/*NOTREACHED*/
.Lhlt:
intel_chip_post_macro(0xee) /* post fe */
hlt
jmp .Lhlt
.globl gdt, gdt_end, gdt_limit
gdt_limit = gdt_end - gdt - 1 /* compute the table limit */
gdtaddr:
.word gdt_limit
.long gdt /* we know the offset */
gdt:
// selgdt 0
.word 0x0000, 0x0000 /* dummy */
.byte 0x00, 0x00, 0x00, 0x00
// selgdt 8
.word 0x0000, 0x0000 /* dummy */
.byte 0x00, 0x00, 0x00, 0x00
// selgdt 0x10
/* flat code segment */
.word 0xffff, 0x0000
.byte 0x00, 0x9b, 0xcf, 0x00
//selgdt 0x18
/* flat data segment */
.word 0xffff, 0x0000
.byte 0x00, 0x93, 0xcf, 0x00
//selgdt 0x20
.word 0x0000, 0x0000 /* dummy */
.byte 0x00, 0x00, 0x00, 0x00
#if defined(CONFIG_VGABIOS) && (CONFIG_VGABIOS == 1)
// from monty:
/* 0x00009a00,0000ffffULL, 20h: 16-bit 64k code at 0x00000000 */
/* 0x00009200,0000ffffULL 28h: 16-bit 64k data at 0x00000000 */
// selgdt 0x28
/*16-bit 64k code at 0x00000000 */
.word 0xffff, 0x0000
.byte 0, 0x9a, 0, 0
// selgdt 0x30
/*16-bit 64k data at 0x00000000 */
.word 0xffff, 0x0000
.byte 0, 0x92, 0, 0
#endif // defined(CONFIG_VGABIOS) && (CONFIG_VGABIOS == 1)
gdt_end:
.code32

119
src/arch/i386/lib/console.c Normal file
View File

@ -0,0 +1,119 @@
#include <console/loglevel.h>
static void __console_tx_byte(unsigned char byte)
{
uart_tx_byte(byte);
}
static void __console_tx_nibble(unsigned nibble)
{
unsigned char digit;
digit = nibble + '0';
if (digit > '9') {
digit += 39;
}
__console_tx_byte(digit);
}
static void __console_tx_char(int loglevel, unsigned char byte)
{
if (ASM_CONSOLE_LOGLEVEL > loglevel) {
uart_tx_byte(byte);
}
}
static void __console_tx_hex8(int loglevel, unsigned char byte)
{
if (ASM_CONSOLE_LOGLEVEL > loglevel) {
__console_tx_nibble(byte >> 4U);
__console_tx_nibble(byte & 0x0fU);
}
}
static void __console_tx_hex32(int loglevel, unsigned int value)
{
if (ASM_CONSOLE_LOGLEVEL > loglevel) {
__console_tx_nibble((value >> 28U) & 0x0fU);
__console_tx_nibble((value >> 24U) & 0x0fU);
__console_tx_nibble((value >> 20U) & 0x0fU);
__console_tx_nibble((value >> 16U) & 0x0fU);
__console_tx_nibble((value >> 12U) & 0x0fU);
__console_tx_nibble((value >> 8U) & 0x0fU);
__console_tx_nibble((value >> 4U) & 0x0fU);
__console_tx_nibble(value & 0x0fU);
}
}
static void __console_tx_string(int loglevel, const char *str)
{
if (ASM_CONSOLE_LOGLEVEL > loglevel) {
unsigned char ch;
while((ch = *str++) != '\0') {
__console_tx_byte(ch);
}
}
}
static void print_emerg_char(unsigned char byte) { __console_tx_char(BIOS_EMERG, byte); }
static void print_emerg_hex8(unsigned char value){ __console_tx_hex8(BIOS_EMERG, value); }
static void print_emerg_hex32(unsigned int value) { __console_tx_hex32(BIOS_EMERG, value); }
static void print_emerg(const char *str) { __console_tx_string(BIOS_EMERG, str); }
static void print_alert_char(unsigned char byte) { __console_tx_char(BIOS_ALERT, byte); }
static void print_alert_hex8(unsigned char value) { __console_tx_hex8(BIOS_ALERT, value); }
static void print_alert_hex32(unsigned int value) { __console_tx_hex32(BIOS_ALERT, value); }
static void print_alert(const char *str) { __console_tx_string(BIOS_ALERT, str); }
static void print_crit_char(unsigned char byte) { __console_tx_char(BIOS_CRIT, byte); }
static void print_crit_hex8(unsigned char value) { __console_tx_hex8(BIOS_CRIT, value); }
static void print_crit_hex32(unsigned int value) { __console_tx_hex32(BIOS_CRIT, value); }
static void print_crit(const char *str) { __console_tx_string(BIOS_CRIT, str); }
static void print_err_char(unsigned char byte) { __console_tx_char(BIOS_ERR, byte); }
static void print_err_hex8(unsigned char value) { __console_tx_hex8(BIOS_ERR, value); }
static void print_err_hex32(unsigned int value) { __console_tx_hex32(BIOS_ERR, value); }
static void print_err(const char *str) { __console_tx_string(BIOS_ERR, str); }
static void print_warning_char(unsigned char byte) { __console_tx_char(BIOS_WARNING, byte); }
static void print_warning_hex8(unsigned char value) { __console_tx_hex8(BIOS_WARNING, value); }
static void print_warning_hex32(unsigned int value) { __console_tx_hex32(BIOS_WARNING, value); }
static void print_warning(const char *str) { __console_tx_string(BIOS_WARNING, str); }
static void print_notice_char(unsigned char byte) { __console_tx_char(BIOS_NOTICE, byte); }
static void print_notice_hex8(unsigned char value) { __console_tx_hex8(BIOS_NOTICE, value); }
static void print_notice_hex32(unsigned int value) { __console_tx_hex32(BIOS_NOTICE, value); }
static void print_notice(const char *str) { __console_tx_string(BIOS_NOTICE, str); }
static void print_info_char(unsigned char byte) { __console_tx_char(BIOS_INFO, byte); }
static void print_info_hex8(unsigned char value) { __console_tx_hex8(BIOS_INFO, value); }
static void print_info_hex32(unsigned int value) { __console_tx_hex32(BIOS_INFO, value); }
static void print_info(const char *str) { __console_tx_string(BIOS_INFO, str); }
static void print_debug_char(unsigned char byte) { __console_tx_char(BIOS_DEBUG, byte); }
static void print_debug_hex8(unsigned char value) { __console_tx_hex8(BIOS_DEBUG, value); }
static void print_debug_hex32(unsigned int value) { __console_tx_hex32(BIOS_DEBUG, value); }
static void print_debug(const char *str) { __console_tx_string(BIOS_DEBUG, str); }
static void print_spew_char(unsigned char byte) { __console_tx_char(BIOS_SPEW, byte); }
static void print_spew_hex8(unsigned char value) { __console_tx_hex8(BIOS_SPEW, value); }
static void print_spew_hex32(unsigned int value) { __console_tx_hex32(BIOS_SPEW, value); }
static void print_spew(const char *str) { __console_tx_string(BIOS_SPEW, str); }
#define __STR(X) #X
#define STR(X) __STR(X)
#ifndef LINUXBIOS_EXTRA_VERSION
#define LINUXBIOS_EXTRA_VERSION
#endif
static void console_init(void)
{
static const char console_test[] =
"\r\n\r\nLinuxBIOS-"
STR(LINUXBIOS_VERSION)
STR(LINUXBIOS_EXTRA_VERSION)
" "
STR(LINUXBIOS_BUILD)
" starting...\r\n";
print_info(console_test);
}

View File

@ -0,0 +1,527 @@
#include <console/loglevel.h>
jmp console0
#define __STR(X) #X
#define STR(X) __STR(X)
#ifndef LINUXBIOS_EXTRA_VERSION
#define LINUXBIOS_EXTRA_VERSION
#endif
console_test:
.ascii "\r\n\r\nLinuxBIOS-"
.ascii STR(LINUXBIOS_VERSION)
.ascii STR(LINUXBIOS_EXTRA_VERSION)
.ascii " "
.ascii STR(LINUXBIOS_BUILD)
.asciz " starting...\r\n"
#undef STR
/* uses: ax, dx */
#if CONFIG_CONSOLE_SERIAL8250
#define __CONSOLE_INLINE_TX_AL TTYS0_TX_AL
#else
#define __CONSOLE_INLINE_TX_AL
#endif
/* uses: esp, ax, dx */
#define __CONSOLE_TX_CHAR(byte) \
mov byte, %al ; \
CALLSP(console_tx_al)
/* uses: ax, dx */
#define __CONSOLE_INLINE_TX_CHAR(byte) \
mov byte, %al ; \
__CONSOLE_INLINE_TX_AL
/* uses: esp, ax, edx */
#define __CONSOLE_TX_HEX8(byte) \
mov byte, %al ; \
CALLSP(console_tx_hex8)
/* uses: byte, ax, dx */
#define __CONSOLE_INLINE_TX_HEX8(byte) \
movb byte, %dl ; \
shll $16, %edx ; \
shr $4, %al ; \
add $'0', %al ; \
cmp $'9', %al ; \
jle 9f ; \
add $39, %al ; \
9: ; \
__CONSOLE_INLINE_TX_AL ; \
shrl $16, %edx ; \
movb %dl, %al ; \
and $0x0f, %al ; \
add $'0', %al ; \
cmp $'9', %al ; \
jle 9f ; \
add $39, %al ; \
9: ; \
__CONSOLE_INLINE_TX_AL
/* uses: esp, eax, ebx, dx */
#define __CONSOLE_TX_HEX32(lword) \
mov lword, %eax ; \
CALLSP(console_tx_hex32)
/* uses: eax, lword, dx */
#define __CONSOLE_INLINE_TX_HEX32(lword) \
mov lword, %eax ; \
shr $28, %eax ; \
add $'0', %al ; \
cmp $'9', %al ; \
jle 9f ; \
add $39, %al ; \
9: ; \
__CONSOLE_INLINE_TX_AL ; \
; \
mov lword, %eax ; \
shr $24, %eax ; \
and $0x0f, %al ; \
add $'0', %al ; \
cmp $'9', %al ; \
jle 9f ; \
add $39, %al ; \
9: ; \
__CONSOLE_INLINE_TX_AL ; \
; \
mov lword, %eax ; \
shr $20, %eax ; \
and $0x0f, %al ; \
add $'0', %al ; \
cmp $'9', %al ; \
jle 9f ; \
add $39, %al ; \
9: ; \
__CONSOLE_INLINE_TX_AL ; \
; \
mov lword, %eax ; \
shr $16, %eax ; \
and $0x0f, %al ; \
add $'0', %al ; \
cmp $'9', %al ; \
jle 9f ; \
add $39, %al ; \
9: ; \
__CONSOLE_INLINE_TX_AL ; \
; \
mov lword, %eax ; \
shr $12, %eax ; \
and $0x0f, %al ; \
add $'0', %al ; \
cmp $'9', %al ; \
jle 9f ; \
add $39, %al ; \
9: ; \
__CONSOLE_INLINE_TX_AL ; \
; \
mov lword, %eax ; \
shr $8, %eax ; \
and $0x0f, %al ; \
add $'0', %al ; \
cmp $'9', %al ; \
jle 9f ; \
add $39, %al ; \
9: ; \
__CONSOLE_INLINE_TX_AL ; \
; \
mov lword, %eax ; \
shr $4, %eax ; \
and $0x0f, %al ; \
add $'0', %al ; \
cmp $'9', %al ; \
jle 9f ; \
add $39, %al ; \
9: ; \
__CONSOLE_INLINE_TX_AL ; \
; \
mov lword, %eax ; \
and $0x0f, %al ; \
add $'0', %al ; \
cmp $'9', %al ; \
jle 9f ; \
add $39, %al ; \
9: ; \
__CONSOLE_INLINE_TX_AL
/* uses: esp, ebx, ax, dx */
#define __CONSOLE_TX_STRING(string) \
mov string, %ebx ; \
CALLSP(console_tx_string)
/* uses: ebx, ax, dx */
#define __CONSOLE_INLINE_TX_STRING(string) \
movl string, %ebx ; \
10: movb (%ebx), %al ; \
incl %ebx ; \
testb %al, %al ; \
jz 11f ; \
__CONSOLE_INLINE_TX_AL ; \
jmp 10b ; \
11:
#define CONSOLE_EMERG_TX_CHAR(byte) __CONSOLE_TX_CHAR(byte)
#define CONSOLE_EMERG_INLINE_TX_CHAR(byte) __CONSOLE_INLINE_TX_CHAR(byte)
#define CONSOLE_EMERG_TX_HEX8(byte) __CONSOLE_TX_HEX8(byte)
#define CONSOLE_EMERG_INLINE_TX_HEX8(byte) __CONSOLE_INLINE_TX_HEX8(byte)
#define CONSOLE_EMERG_TX_HEX32(lword) __CONSOLE_TX_HEX32(lword)
#define CONSOLE_EMERG_INLINE_TX_HEX32(lword) __CONSOLE_INLINE_TX_HEX32(lword)
#define CONSOLE_EMERG_TX_STRING(string) __CONSOLE_TX_STRING(string)
#define CONSOLE_EMERG_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string)
#define CONSOLE_ALERT_TX_CHAR(byte) __CONSOLE_TX_CHAR(byte)
#define CONSOLE_ALERT_INLINE_TX_CHAR(byte) __CONSOLE_INLINE_TX_CHAR(byte)
#define CONSOLE_ALERT_TX_HEX8(byte) __CONSOLE_TX_HEX8(byte)
#define CONSOLE_ALERT_INLINE_TX_HEX8(byte) __CONSOLE_INLINE_TX_HEX8(byte)
#define CONSOLE_ALERT_TX_HEX32(lword) __CONSOLE_TX_HEX32(lword)
#define CONSOLE_ALERT_INLINE_TX_HEX32(lword) __CONSOLE_INLINE_TX_HEX32(lword)
#define CONSOLE_ALERT_TX_STRING(string) __CONSOLE_TX_STRING(string)
#define CONSOLE_ALERT_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string)
#define CONSOLE_CRIT_TX_CHAR(byte) __CONSOLE_TX_CHAR(byte)
#define CONSOLE_CRIT_INLINE_TX_CHAR(byte) __CONSOLE_INLINE_TX_CHAR(byte)
#define CONSOLE_CRIT_TX_HEX8(byte) __CONSOLE_TX_HEX8(byte)
#define CONSOLE_CRIT_INLINE_TX_HEX8(byte) __CONSOLE_INLINE_TX_HEX8(byte)
#define CONSOLE_CRIT_TX_HEX32(lword) __CONSOLE_TX_HEX32(lword)
#define CONSOLE_CRIT_INLINE_TX_HEX32(lword) __CONSOLE_INLINE_TX_HEX32(lword)
#define CONSOLE_CRIT_TX_STRING(string) __CONSOLE_TX_STRING(string)
#define CONSOLE_CRIT_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string)
#define CONSOLE_ERR_TX_CHAR(byte) __CONSOLE_TX_CHAR(byte)
#define CONSOLE_ERR_INLINE_TX_CHAR(byte) __CONSOLE_INLINE_TX_CHAR(byte)
#define CONSOLE_ERR_TX_HEX8(byte) __CONSOLE_TX_HEX8(byte)
#define CONSOLE_ERR_INLINE_TX_HEX8(byte) __CONSOLE_INLINE_TX_HEX8(byte)
#define CONSOLE_ERR_TX_HEX32(lword) __CONSOLE_TX_HEX32(lword)
#define CONSOLE_ERR_INLINE_TX_HEX32(lword) __CONSOLE_INLINE_TX_HEX32(lword)
#define CONSOLE_ERR_TX_STRING(string) __CONSOLE_TX_STRING(string)
#define CONSOLE_ERR_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string)
#define CONSOLE_WARNING_TX_CHAR(byte) __CONSOLE_TX_CHAR(byte)
#define CONSOLE_WARNING_INLINE_TX_CHAR(byte) __CONSOLE_INLINE_TX_CHAR(byte)
#define CONSOLE_WARNING_TX_HEX8(byte) __CONSOLE_TX_HEX8(byte)
#define CONSOLE_WARNING_INLINE_TX_HEX8(byte) __CONSOLE_INLINE_TX_HEX8(byte)
#define CONSOLE_WARNING_TX_HEX32(lword) __CONSOLE_TX_HEX32(lword)
#define CONSOLE_WARNING_INLINE_TX_HEX32(lword) __CONSOLE_INLINE_TX_HEX32(lword)
#define CONSOLE_WARNING_TX_STRING(string) __CONSOLE_TX_STRING(string)
#define CONSOLE_WARNING_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string)
#define CONSOLE_NOTICE_TX_CHAR(byte) __CONSOLE_TX_CHAR(byte)
#define CONSOLE_NOTICE_INLINE_TX_CHAR(byte) __CONSOLE_INLINE_TX_CHAR(byte)
#define CONSOLE_NOTICE_TX_HEX8(byte) __CONSOLE_TX_HEX8(byte)
#define CONSOLE_NOTICE_INLINE_TX_HEX8(byte) __CONSOLE_INLINE_TX_HEX8(byte)
#define CONSOLE_NOTICE_TX_HEX32(lword) __CONSOLE_TX_HEX32(lword)
#define CONSOLE_NOTICE_INLINE_TX_HEX32(lword) __CONSOLE_INLINE_TX_HEX32(lword)
#define CONSOLE_NOTICE_TX_STRING(string) __CONSOLE_TX_STRING(string)
#define CONSOLE_NOTICE_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string)
#define CONSOLE_INFO_TX_CHAR(byte) __CONSOLE_TX_CHAR(byte)
#define CONSOLE_INFO_INLINE_TX_CHAR(byte) __CONSOLE_INLINE_TX_CHAR(byte)
#define CONSOLE_INFO_TX_HEX8(byte) __CONSOLE_TX_HEX8(byte)
#define CONSOLE_INFO_INLINE_TX_HEX8(byte) __CONSOLE_INLINE_TX_HEX8(byte)
#define CONSOLE_INFO_TX_HEX32(lword) __CONSOLE_TX_HEX32(lword)
#define CONSOLE_INFO_INLINE_TX_HEX32(lword) __CONSOLE_INLINE_TX_HEX32(lword)
#define CONSOLE_INFO_TX_STRING(string) __CONSOLE_TX_STRING(string)
#define CONSOLE_INFO_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string)
#define CONSOLE_DEBUG_TX_CHAR(byte) __CONSOLE_TX_CHAR(byte)
#define CONSOLE_DEBUG_INLINE_TX_CHAR(byte) __CONSOLE_INLINE_TX_CHAR(byte)
#define CONSOLE_DEBUG_TX_HEX8(byte) __CONSOLE_TX_HEX8(byte)
#define CONSOLE_DEBUG_INLINE_TX_HEX8(byte) __CONSOLE_INLINE_TX_HEX8(byte)
#define CONSOLE_DEBUG_TX_HEX32(lword) __CONSOLE_TX_HEX32(lword)
#define CONSOLE_DEBUG_INLINE_TX_HEX32(lword) __CONSOLE_INLINE_TX_HEX32(lword)
#define CONSOLE_DEBUG_TX_STRING(string) __CONSOLE_TX_STRING(string)
#define CONSOLE_DEBUG_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string)
#define CONSOLE_SPEW_TX_CHAR(byte) __CONSOLE_TX_CHAR(byte)
#define CONSOLE_SPEW_INLINE_TX_CHAR(byte) __CONSOLE_INLINE_TX_CHAR(byte)
#define CONSOLE_SPEW_TX_HEX8(byte) __CONSOLE_TX_HEX8(byte)
#define CONSOLE_SPEW_INLINE_TX_HEX8(byte) __CONSOLE_INLINE_TX_HEX8(byte)
#define CONSOLE_SPEW_TX_HEX32(lword) __CONSOLE_TX_HEX32(lword)
#define CONSOLE_SPEW_INLINE_TX_HEX32(lword) __CONSOLE_INLINE_TX_HEX32(lword)
#define CONSOLE_SPEW_TX_STRING(string) __CONSOLE_TX_STRING(string)
#define CONSOLE_SPEW_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string)
#if ASM_CONSOLE_LOGLEVEL <= BIOS_EMERG
#undef CONSOLE_EMERG_TX_CHAR
#undef CONSOLE_EMERG_INLINE_TX_CHAR
#undef CONSOLE_EMERG_TX_HEX8
#undef CONSOLE_EMERG_INLINE_TX_HEX8
#undef CONSOLE_EMERG_TX_HEX32
#undef CONSOLE_EMERG_INLINE_TX_HEX32
#undef CONSOLE_EMERG_TX_STRING
#undef CONSOLE_EMERG_INLINE_TX_STRING
#define CONSOLE_EMERG_TX_CHAR(byte)
#define CONSOLE_EMERG_INLINE_TX_CHAR(byte)
#define CONSOLE_EMERG_TX_HEX8(byte)
#define CONSOLE_EMERG_INLINE_TX_HEX8(byte)
#define CONSOLE_EMERG_TX_HEX32(lword)
#define CONSOLE_EMERG_INLINE_TX_HEX32(lword)
#define CONSOLE_EMERG_TX_STRING(string)
#define CONSOLE_EMERG_INLINE_TX_STRING(string)
#endif
#if ASM_CONSOLE_LOGLEVEL <= BIOS_ALERT
#undef CONSOLE_ALERT_TX_CHAR
#undef CONSOLE_ALERT_INLINE_TX_CHAR
#undef CONSOLE_ALERT_TX_HEX8
#undef CONSOLE_ALERT_INLINE_TX_HEX8
#undef CONSOLE_ALERT_TX_HEX32
#undef CONSOLE_ALERT_INLINE_TX_HEX32
#undef CONSOLE_ALERT_TX_STRING
#undef CONSOLE_ALERT_INLINE_TX_STRING
#define CONSOLE_ALERT_TX_CHAR(byte)
#define CONSOLE_ALERT_INLINE_TX_CHAR(byte)
#define CONSOLE_ALERT_TX_HEX8(byte)
#define CONSOLE_ALERT_INLINE_TX_HEX8(byte)
#define CONSOLE_ALERT_TX_HEX32(lword)
#define CONSOLE_ALERT_INLINE_TX_HEX32(lword)
#define CONSOLE_ALERT_TX_STRING(string)
#define CONSOLE_ALERT_INLINE_TX_STRING(string)
#endif
#if ASM_CONSOLE_LOGLEVEL <= BIOS_CRIT
#undef CONSOLE_CRIT_TX_CHAR
#undef CONSOLE_CRIT_INLINE_TX_CHAR
#undef CONSOLE_CRIT_TX_HEX8
#undef CONSOLE_CRIT_INLINE_TX_HEX8
#undef CONSOLE_CRIT_TX_HEX32
#undef CONSOLE_CRIT_INLINE_TX_HEX32
#undef CONSOLE_CRIT_TX_STRING
#undef CONSOLE_CRIT_INLINE_TX_STRING
#define CONSOLE_CRIT_TX_CHAR(byte)
#define CONSOLE_CRIT_INLINE_TX_CHAR(byte)
#define CONSOLE_CRIT_TX_HEX8(byte)
#define CONSOLE_CRIT_INLINE_TX_HEX8(byte)
#define CONSOLE_CRIT_TX_HEX32(lword)
#define CONSOLE_CRIT_INLINE_TX_HEX32(lword)
#define CONSOLE_CRIT_TX_STRING(string)
#define CONSOLE_CRIT_INLINE_TX_STRING(string)
#endif
#if ASM_CONSOLE_LOGLEVEL <= BIOS_ERR
#undef CONSOLE_ERR_TX_CHAR
#undef CONSOLE_ERR_INLINE_TX_CHAR
#undef CONSOLE_ERR_TX_HEX8
#undef CONSOLE_ERR_INLINE_TX_HEX8
#undef CONSOLE_ERR_TX_HEX32
#undef CONSOLE_ERR_INLINE_TX_HEX32
#undef CONSOLE_ERR_TX_STRING
#undef CONSOLE_ERR_INLINE_TX_STRING
#define CONSOLE_ERR_TX_CHAR(byte)
#define CONSOLE_ERR_INLINE_TX_CHAR(byte)
#define CONSOLE_ERR_TX_HEX8(byte)
#define CONSOLE_ERR_INLINE_TX_HEX8(byte)
#define CONSOLE_ERR_TX_HEX32(lword)
#define CONSOLE_ERR_INLINE_TX_HEX32(lword)
#define CONSOLE_ERR_TX_STRING(string)
#define CONSOLE_ERR_INLINE_TX_STRING(string)
#endif
#if ASM_CONSOLE_LOGLEVEL <= BIOS_WARNING
#undef CONSOLE_WARNING_TX_CHAR
#undef CONSOLE_WARNING_INLINE_TX_CHAR
#undef CONSOLE_WARNING_TX_HEX8
#undef CONSOLE_WARNING_INLINE_TX_HEX8
#undef CONSOLE_WARNING_TX_HEX32
#undef CONSOLE_WARNING_INLINE_TX_HEX32
#undef CONSOLE_WARNING_TX_STRING
#undef CONSOLE_WARNING_INLINE_TX_STRING
#define CONSOLE_WARNING_TX_CHAR(byte)
#define CONSOLE_WARNING_INLINE_TX_CHAR(byte)
#define CONSOLE_WARNING_TX_HEX8(byte)
#define CONSOLE_WARNING_INLINE_TX_HEX8(byte)
#define CONSOLE_WARNING_TX_HEX32(lword)
#define CONSOLE_WARNING_INLINE_TX_HEX32(lword)
#define CONSOLE_WARNING_TX_STRING(string)
#define CONSOLE_WARNING_INLINE_TX_STRING(string)
#endif
#if ASM_CONSOLE_LOGLEVEL <= BIOS_NOTICE
#undef CONSOLE_NOTICE_TX_CHAR
#undef CONSOLE_NOTICE_INLINE_TX_CHAR
#undef CONSOLE_NOTICE_TX_HEX8
#undef CONSOLE_NOTICE_INLINE_TX_HEX8
#undef CONSOLE_NOTICE_TX_HEX32
#undef CONSOLE_NOTICE_INLINE_TX_HEX32
#undef CONSOLE_NOTICE_TX_STRING
#undef CONSOLE_NOTICE_INLINE_TX_STRING
#define CONSOLE_NOTICE_TX_CHAR(byte)
#define CONSOLE_NOTICE_INLINE_TX_CHAR(byte)
#define CONSOLE_NOTICE_TX_HEX8(byte)
#define CONSOLE_NOTICE_INLINE_TX_HEX8(byte)
#define CONSOLE_NOTICE_TX_HEX32(lword)
#define CONSOLE_NOTICE_INLINE_TX_HEX32(lword)
#define CONSOLE_NOTICE_TX_STRING(string)
#define CONSOLE_NOTICE_INLINE_TX_STRING(string)
#endif
#if ASM_CONSOLE_LOGLEVEL <= BIOS_INFO
#undef CONSOLE_INFO_TX_CHAR
#undef CONSOLE_INFO_INLINE_TX_CHAR
#undef CONSOLE_INFO_TX_HEX8
#undef CONSOLE_INFO_INLINE_TX_HEX8
#undef CONSOLE_INFO_TX_HEX32
#undef CONSOLE_INFO_INLINE_TX_HEX32
#undef CONSOLE_INFO_TX_STRING
#undef CONSOLE_INFO_INLINE_TX_STRING
#define CONSOLE_INFO_TX_CHAR(byte)
#define CONSOLE_INFO_INLINE_TX_CHAR(byte)
#define CONSOLE_INFO_TX_HEX8(byte)
#define CONSOLE_INFO_INLINE_TX_HEX8(byte)
#define CONSOLE_INFO_TX_HEX32(lword)
#define CONSOLE_INFO_INLINE_TX_HEX32(lword)
#define CONSOLE_INFO_TX_STRING(string)
#define CONSOLE_INFO_INLINE_TX_STRING(string)
#endif
#if ASM_CONSOLE_LOGLEVEL <= BIOS_DEBUG
#undef CONSOLE_DEBUG_TX_CHAR
#undef CONSOLE_DEBUG_INLINE_TX_CHAR
#undef CONSOLE_DEBUG_TX_HEX8
#undef CONSOLE_DEBUG_INLINE_TX_HEX8
#undef CONSOLE_DEBUG_TX_HEX32
#undef CONSOLE_DEBUG_INLINE_TX_HEX32
#undef CONSOLE_DEBUG_TX_STRING
#undef CONSOLE_DEBUG_INLINE_TX_STRING
#define CONSOLE_DEBUG_TX_CHAR(byte)
#define CONSOLE_DEBUG_INLINE_TX_CHAR(byte)
#define CONSOLE_DEBUG_TX_HEX8(byte)
#define CONSOLE_DEBUG_INLINE_TX_HEX8(byte)
#define CONSOLE_DEBUG_TX_HEX32(lword)
#define CONSOLE_DEBUG_INLINE_TX_HEX32(lword)
#define CONSOLE_DEBUG_TX_STRING(string)
#define CONSOLE_DEBUG_INLINE_TX_STRING(string)
#endif
#if ASM_CONSOLE_LOGLEVEL <= BIOS_SPEW
#undef CONSOLE_SPEW_TX_CHAR
#undef CONSOLE_SPEW_INLINE_TX_CHAR
#undef CONSOLE_SPEW_TX_HEX8
#undef CONSOLE_SPEW_INLINE_TX_HEX8
#undef CONSOLE_SPEW_TX_HEX32
#undef CONSOLE_SPEW_INLINE_TX_HEX32
#undef CONSOLE_SPEW_TX_STRING
#undef CONSOLE_SPEW_INLINE_TX_STRING
#define CONSOLE_SPEW_TX_CHAR(byte)
#define CONSOLE_SPEW_INLINE_TX_CHAR(byte)
#define CONSOLE_SPEW_TX_HEX8(byte)
#define CONSOLE_SPEW_INLINE_TX_HEX8(byte)
#define CONSOLE_SPEW_TX_HEX32(lword)
#define CONSOLE_SPEW_INLINE_TX_HEX32(lword)
#define CONSOLE_SPEW_TX_STRING(string)
#define CONSOLE_SPEW_INLINE_TX_STRING(string)
#endif
/* uses: esp, ax, dx */
console_tx_al:
__CONSOLE_INLINE_TX_AL
RETSP
/* uses: esp, ax, edx */
console_tx_hex8:
__CONSOLE_INLINE_TX_HEX8(%al)
RETSP
/* uses: esp, ebx, eax, dx */
console_tx_hex32:
mov %eax, %ebx
shr $28, %eax
add $'0', %al
cmp $'9', %al
jle 9f
add $39, %al
9:
__CONSOLE_INLINE_TX_AL
mov %ebx, %eax
shr $24, %eax
and $0x0f, %al
add $'0', %al
cmp $'9', %al
jle 9f
add $39, %al
9:
__CONSOLE_INLINE_TX_AL
mov %ebx, %eax
shr $20, %eax
and $0x0f, %al
add $'0', %al
cmp $'9', %al
jle 9f
add $39, %al
9:
__CONSOLE_INLINE_TX_AL
mov %ebx, %eax
shr $16, %eax
and $0x0f, %al
add $'0', %al
cmp $'9', %al
jle 9f
add $39, %al
9:
__CONSOLE_INLINE_TX_AL
mov %ebx, %eax
shr $12, %eax
and $0x0f, %al
add $'0', %al
cmp $'9', %al
jle 9f
add $39, %al
9:
__CONSOLE_INLINE_TX_AL
mov %ebx, %eax
shr $8, %eax
and $0x0f, %al
add $'0', %al
cmp $'9', %al
jle 9f
add $39, %al
9:
__CONSOLE_INLINE_TX_AL
mov %ebx, %eax
shr $4, %eax
and $0x0f, %al
add $'0', %al
cmp $'9', %al
jle 9f
add $39, %al
9:
__CONSOLE_INLINE_TX_AL
mov %ebx, %eax
and $0x0f, %al
add $'0', %al
cmp $'9', %al
jle 9f
add $39, %al
9:
__CONSOLE_INLINE_TX_AL
RETSP
/* Uses esp, ebx, ax, dx */
console_tx_string:
mov (%ebx), %al
inc %ebx
cmp $0, %al
jne 9f
RETSP
9:
__CONSOLE_INLINE_TX_AL
jmp console_tx_string
console0:
CONSOLE_INFO_TX_STRING($console_test)

139
src/arch/i386/lib/cpu.c Normal file
View File

@ -0,0 +1,139 @@
#include <console/console.h>
#include <cpu/cpu.h>
#include <mem.h>
#include <arch/io.h>
#include <string.h>
#include <cpu/cpufixup.h>
#include <smp/start_stop.h>
#include <cpu/cpufixup.h>
#include <cpu/p6/mtrr.h>
#include <cpu/p6/msr.h>
#include <cpu/p6/apic.h>
#include <cpu/p5/cpuid.h>
#if 0
#include <cpu/l2_cache.h>
#endif
#if CONFIG_SMP || CONFIG_IOAPIC
#define APIC 1
#endif
static void cache_on(struct mem_range *mem)
{
post_code(0x60);
printk_info("Enabling cache...");
/* we need an #ifdef i586 here at some point ... */
__asm__ __volatile__("mov %cr0, %eax\n\t"
"and $0x9fffffff,%eax\n\t"
"mov %eax, %cr0\n\t");
/* turns out cache isn't really on until you set MTRR registers on
* 686 and later.
* NOTHING FANCY. Linux does a much better job anyway.
* so absolute minimum needed to get it going.
*/
/* OK, linux it turns out does nothing. We have to do it ... */
#if defined(i686)
// totalram here is in linux sizing, i.e. units of KB.
// set_mtrr is responsible for getting it into the right units!
setup_mtrrs(mem);
#endif
post_code(0x6A);
printk_info("done.\n");
}
static void interrupts_on()
{
/* this is so interrupts work. This is very limited scope --
* linux will do better later, we hope ...
*/
/* this is the first way we learned to do it. It fails on real SMP
* stuff. So we have to do things differently ...
* see the Intel mp1.4 spec, page A-3
*/
#if defined(APIC)
/* Only Pentium Pro and later have those MSR stuff */
unsigned long low, high;
printk_info("Setting up local apic...");
/* Enable the local apic */
rdmsr(APIC_BASE_MSR, low, high);
low |= APIC_BASE_MSR_ENABLE;
low &= ~APIC_BASE_MSR_ADDR_MASK;
low |= APIC_DEFAULT_BASE;
wrmsr(APIC_BASE_MSR, low, high);
/* Put the local apic in virtual wire mode */
apic_write_around(APIC_SPIV,
(apic_read_around(APIC_SPIV) & ~(APIC_VECTOR_MASK))
| APIC_SPIV_ENABLE);
apic_write_around(APIC_LVT0,
(apic_read_around(APIC_LVT0) &
~(APIC_LVT_MASKED | APIC_LVT_LEVEL_TRIGGER |
APIC_LVT_REMOTE_IRR | APIC_INPUT_POLARITY |
APIC_SEND_PENDING |APIC_LVT_RESERVED_1 |
APIC_DELIVERY_MODE_MASK))
| (APIC_LVT_REMOTE_IRR |APIC_SEND_PENDING |
APIC_DELIVERY_MODE_EXTINT)
);
apic_write_around(APIC_LVT1,
(apic_read_around(APIC_LVT1) &
~(APIC_LVT_MASKED | APIC_LVT_LEVEL_TRIGGER |
APIC_LVT_REMOTE_IRR | APIC_INPUT_POLARITY |
APIC_SEND_PENDING |APIC_LVT_RESERVED_1 |
APIC_DELIVERY_MODE_MASK))
| (APIC_LVT_REMOTE_IRR |APIC_SEND_PENDING |
APIC_DELIVERY_MODE_NMI)
);
#else /* APIC */
#ifdef i686
/* Only Pentium Pro and later have those MSR stuff */
unsigned long low, high;
printk_info("Disabling local apic...");
rdmsr(APIC_BASE_MSR, low, high);
low &= ~APIC_BASE_MSR_ENABLE;
wrmsr(APIC_BASE_MSR, low, high);
#endif /* i686 */
#endif /* APIC */
printk_info("done.\n");
post_code(0x9b);
}
unsigned long cpu_initialize(struct mem_range *mem)
{
/* Because we busy wait at the printk spinlock.
* It is important to keep the number of printed messages
* from secondary cpus to a minimum, when debugging is
* disabled.
*/
unsigned long processor_id = this_processors_id();
printk_notice("Initializing CPU #%d\n", processor_id);
/* some cpus need a fixup done. This is the hook for doing that. */
cpufixup(mem);
/* Turn on caching if we haven't already */
cache_on(mem);
display_cpuid();
mtrr_check();
#if 0
/* now that everything is really up, enable the l2 cache if desired.
* The enable can wait until this point, because linuxbios and it's
* data areas are tiny, easily fitting into the L1 cache.
*/
configure_l2_cache();
#endif
interrupts_on();
printk_info("CPU #%d Initialized\n", processor_id);
return processor_id;
}

View File

@ -0,0 +1,9 @@
jmp cpu_reset_out
__cpu_reset:
movl $0xffffffff, %ebp
jmp __main
cpu_reset_out:

View File

@ -0,0 +1 @@
__normal_image = (ZKERNEL_START & 0xfffffff0) - 8;

21
src/arch/i386/lib/id.inc Normal file
View File

@ -0,0 +1,21 @@
.section ".id", "a", @progbits
#define __STR(X) #X
#define STR(X) __STR(X)
.globl __id_start
__id_start:
vendor:
.asciz STR(MAINBOARD_VENDOR)
part:
.asciz STR(MAINBOARD_PART_NUMBER)
.long __id_end + 0x10 - vendor /* Reverse offset to the vendor id */
.long __id_end + 0x10 - part /* Reverse offset to the part number */
.long PAYLOAD_SIZE + ROM_IMAGE_SIZE /* Size of this romimage */
.globl __id_end
#undef __STR
#undef STR
__id_end:
.previous

6
src/arch/i386/lib/id.lds Normal file
View File

@ -0,0 +1,6 @@
SECTIONS {
. = (_ROMBASE + ROM_IMAGE_SIZE - 0x10) - (__id_end - __id_start);
.id (.): {
*(.id)
}
}

View File

@ -0,0 +1,9 @@
/* Step 1: Test for cpu reset
* That is, did I just boot or is this a later boot since power on.
* The result of this test in %al
* %al == 1 -- We are rebooting
* %al == 0 -- This is the initial boot
*
*/
testb %al, %al
jnz __cpu_reset

281
src/arch/i386/lib/pci_ops.c Normal file
View File

@ -0,0 +1,281 @@
#include <console/console.h>
#include <arch/io.h>
#include <arch/pciconf.h>
#include <pci.h>
#include <pci_ids.h>
#include <pci_ops.h>
static const struct pci_ops *conf;
struct pci_ops {
int (*read_byte) (uint8_t bus, int devfn, int where, uint8_t * val);
int (*read_word) (uint8_t bus, int devfn, int where, uint16_t * val);
int (*read_dword) (uint8_t bus, int devfn, int where, uint32_t * val);
int (*write_byte) (uint8_t bus, int devfn, int where, uint8_t val);
int (*write_word) (uint8_t bus, int devfn, int where, uint16_t val);
int (*write_dword) (uint8_t bus, int devfn, int where, uint32_t val);
};
/*
* Direct access to PCI hardware...
*/
/*
* Functions for accessing PCI configuration space with type 1 accesses
*/
#define CONFIG_CMD(bus,devfn, where) (0x80000000 | (bus << 16) | (devfn << 8) | (where & ~3))
static int pci_conf1_read_config_byte(unsigned char bus, int devfn, int where, uint8_t * value)
{
outl(CONFIG_CMD(bus, devfn, where), 0xCF8);
*value = inb(0xCFC + (where & 3));
return 0;
}
static int pci_conf1_read_config_word(unsigned char bus, int devfn, int where, uint16_t * value)
{
outl(CONFIG_CMD(bus, devfn, where), 0xCF8);
*value = inw(0xCFC + (where & 2));
return 0;
}
static int pci_conf1_read_config_dword(unsigned char bus, int devfn, int where, uint32_t * value)
{
outl(CONFIG_CMD(bus, devfn, where), 0xCF8);
*value = inl(0xCFC);
return 0;
}
static int pci_conf1_write_config_byte(unsigned char bus, int devfn, int where, uint8_t value)
{
outl(CONFIG_CMD(bus, devfn, where), 0xCF8);
outb(value, 0xCFC + (where & 3));
return 0;
}
static int pci_conf1_write_config_word(unsigned char bus, int devfn, int where, uint16_t value)
{
outl(CONFIG_CMD(bus, devfn, where), 0xCF8);
outw(value, 0xCFC + (where & 2));
return 0;
}
static int pci_conf1_write_config_dword(unsigned char bus, int devfn, int where, uint32_t value)
{
outl(CONFIG_CMD(bus, devfn, where), 0xCF8);
outl(value, 0xCFC);
return 0;
}
#undef CONFIG_CMD
static const struct pci_ops pci_direct_conf1 =
{
pci_conf1_read_config_byte,
pci_conf1_read_config_word,
pci_conf1_read_config_dword,
pci_conf1_write_config_byte,
pci_conf1_write_config_word,
pci_conf1_write_config_dword
};
/*
* Functions for accessing PCI configuration space with type 2 accesses
*/
#define IOADDR(devfn, where) ((0xC000 | ((devfn & 0x78) << 5)) + where)
#define FUNC(devfn) (((devfn & 7) << 1) | 0xf0)
#define SET(bus,devfn) if (devfn & 0x80) return -1;outb(FUNC(devfn), 0xCF8); outb(bus, 0xCFA);
static int pci_conf2_read_config_byte(unsigned char bus, int devfn, int where, uint8_t * value)
{
SET(bus, devfn);
*value = inb(IOADDR(devfn, where));
outb(0, 0xCF8);
return 0;
}
static int pci_conf2_read_config_word(unsigned char bus, int devfn, int where, uint16_t * value)
{
SET(bus, devfn);
*value = inw(IOADDR(devfn, where));
outb(0, 0xCF8);
return 0;
}
static int pci_conf2_read_config_dword(unsigned char bus, int devfn, int where, uint32_t * value)
{
SET(bus, devfn);
*value = inl(IOADDR(devfn, where));
outb(0, 0xCF8);
return 0;
}
static int pci_conf2_write_config_byte(unsigned char bus, int devfn, int where, uint8_t value)
{
SET(bus, devfn);
outb(value, IOADDR(devfn, where));
outb(0, 0xCF8);
return 0;
}
static int pci_conf2_write_config_word(unsigned char bus, int devfn, int where, uint16_t value)
{
SET(bus, devfn);
outw(value, IOADDR(devfn, where));
outb(0, 0xCF8);
return 0;
}
static int pci_conf2_write_config_dword(unsigned char bus, int devfn, int where, uint32_t value)
{
SET(bus, devfn);
outl(value, IOADDR(devfn, where));
outb(0, 0xCF8);
return 0;
}
#undef SET
#undef IOADDR
#undef FUNC
static const struct pci_ops pci_direct_conf2 =
{
pci_conf2_read_config_byte,
pci_conf2_read_config_word,
pci_conf2_read_config_dword,
pci_conf2_write_config_byte,
pci_conf2_write_config_word,
pci_conf2_write_config_dword
};
/*
* Before we decide to use direct hardware access mechanisms, we try to do some
* trivial checks to ensure it at least _seems_ to be working -- we just test
* whether bus 00 contains a host bridge (this is similar to checking
* techniques used in XFree86, but ours should be more reliable since we
* attempt to make use of direct access hints provided by the PCI BIOS).
*
* This should be close to trivial, but it isn't, because there are buggy
* chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID.
*/
static int pci_sanity_check(const struct pci_ops *o)
{
uint16_t x;
uint8_t bus;
int devfn;
#define PCI_CLASS_BRIDGE_HOST 0x0600
#define PCI_CLASS_DISPLAY_VGA 0x0300
#define PCI_VENDOR_ID_COMPAQ 0x0e11
#define PCI_VENDOR_ID_INTEL 0x8086
#define PCI_VENDOR_ID_MOTOROLA 0x1057
for (bus = 0, devfn = 0; devfn < 0x100; devfn++)
if ((!o->read_word(bus, devfn, PCI_CLASS_DEVICE, &x) &&
(x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA)) ||
(!o->read_word(bus, devfn, PCI_VENDOR_ID, &x) &&
(x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ || x == PCI_VENDOR_ID_MOTOROLA)))
return 1;
printk_err("PCI: Sanity check failed\n");
return 0;
}
static const struct pci_ops *pci_check_direct(void)
{
unsigned int tmp;
/*
* Check if configuration type 1 works.
*/
{
outb(0x01, 0xCFB);
tmp = inl(0xCF8);
outl(0x80000000, 0xCF8);
if (inl(0xCF8) == 0x80000000 &&
pci_sanity_check(&pci_direct_conf1)) {
outl(tmp, 0xCF8);
printk_debug("PCI: Using configuration type 1\n");
return &pci_direct_conf1;
}
outl(tmp, 0xCF8);
}
/*
* Check if configuration type 2 works.
*/
{
outb(0x00, 0xCFB);
outb(0x00, 0xCF8);
outb(0x00, 0xCFA);
if (inb(0xCF8) == 0x00 && inb(0xCFA) == 0x00 &&
pci_sanity_check(&pci_direct_conf2)) {
printk_debug("PCI: Using configuration type 2\n");
return &pci_direct_conf2;
}
}
printk_debug("pci_check_direct failed\n");
return 0;
}
int pci_read_config_byte(struct device *dev, uint8_t where, uint8_t * val)
{
int res;
res = conf->read_byte(dev->bus->secondary, dev->devfn, where, val);
printk_spew("Read config byte bus %d,devfn 0x%x,reg 0x%x,val 0x%x,res 0x%x\n",
dev->bus->secondary, dev->devfn, where, *val, res);
return res;
}
int pci_read_config_word(struct device *dev, uint8_t where, uint16_t * val)
{
int res;
res = conf->read_word(dev->bus->secondary, dev->devfn, where, val);
printk_spew( "Read config word bus %d,devfn 0x%x,reg 0x%x,val 0x%x,res 0x%x\n",
dev->bus->secondary, dev->devfn, where, *val, res);
return res;
}
int pci_read_config_dword(struct device *dev, uint8_t where, uint32_t * val)
{
int res;
res = conf->read_dword(dev->bus->secondary, dev->devfn, where, val);
printk_spew( "Read config dword bus %d,devfn 0x%x,reg 0x%x,val 0x%x,res 0x%x\n",
dev->bus->secondary, dev->devfn, where, *val, res);
return res;
}
int pci_write_config_byte(struct device *dev, uint8_t where, uint8_t val)
{
printk_spew( "Write config byte bus %d, devfn 0x%x, reg 0x%x, val 0x%x\n",
dev->bus->secondary, dev->devfn, where, val);
return conf->write_byte(dev->bus->secondary, dev->devfn, where, val);
}
int pci_write_config_word(struct device *dev, uint8_t where, uint16_t val)
{
printk_spew( "Write config word bus %d, devfn 0x%x, reg 0x%x, val 0x%x\n",
dev->bus->secondary, dev->devfn, where, val);
return conf->write_word(dev->bus->secondary, dev->devfn, where, val);
}
int pci_write_config_dword(struct device *dev, uint8_t where, uint32_t val)
{
printk_spew( "Write config dword bus %d, devfn 0x%x, reg 0x%x, val 0x%x\n",
dev->bus->secondary, dev->devfn, where, val);
return conf->write_dword(dev->bus->secondary, dev->devfn, where, val);
}
/** Set the method to be used for PCI, type I or type II
*/
void pci_set_method(void)
{
conf = &pci_direct_conf1;
conf = pci_check_direct();
}

245
src/arch/i386/smp/mpspec.c Normal file
View File

@ -0,0 +1,245 @@
#include <console/console.h>
#include <cpu/cpu.h>
#include <smp/start_stop.h>
#include <arch/smp/mpspec.h>
#include <string.h>
#include <cpu/p5/cpuid.h>
#include <cpu/p6/apic.h>
unsigned char smp_compute_checksum(void *v, int len)
{
unsigned char *bytes;
unsigned char checksum;
int i;
bytes = v;
checksum = 0;
for(i = 0; i < len; i++) {
checksum -= bytes[i];
}
return checksum;
}
void *smp_write_floating_table(unsigned long addr)
{
struct intel_mp_floating *mf;
void *v;
/* 16 byte align the table address */
addr += 15;
addr &= ~15;
v = (void *)addr;
mf = v;
mf->mpf_signature[0] = '_';
mf->mpf_signature[1] = 'M';
mf->mpf_signature[2] = 'P';
mf->mpf_signature[3] = '_';
mf->mpf_physptr = (unsigned long)(((char *)v) + SMP_FLOATING_TABLE_LEN);
mf->mpf_length = 1;
mf->mpf_specification = 4;
mf->mpf_checksum = 0;
mf->mpf_feature1 = 0;
mf->mpf_feature2 = 0;
mf->mpf_feature3 = 0;
mf->mpf_feature4 = 0;
mf->mpf_feature5 = 0;
mf->mpf_checksum = smp_compute_checksum(mf, mf->mpf_length*16);
return v;
}
void *smp_next_mpc_entry(struct mp_config_table *mc)
{
void *v;
v = (void *)(((char *)mc) + mc->mpc_length);
return v;
}
static void smp_add_mpc_entry(struct mp_config_table *mc, unsigned length)
{
mc->mpc_length += length;
mc->mpc_entry_count++;
}
void *smp_next_mpe_entry(struct mp_config_table *mc)
{
void *v;
v = (void *)(((char *)mc) + mc->mpc_length + mc->mpe_length);
return v;
}
static void smp_add_mpe_entry(struct mp_config_table *mc, mpe_t mpe)
{
mc->mpe_length += mpe->mpe_length;
}
void smp_write_processor(struct mp_config_table *mc,
unsigned char apicid, unsigned char apicver,
unsigned char cpuflag, unsigned int cpufeature,
unsigned int featureflag)
{
struct mpc_config_processor *mpc;
mpc = smp_next_mpc_entry(mc);
memset(mpc, '\0', sizeof(*mpc));
mpc->mpc_type = MP_PROCESSOR;
mpc->mpc_apicid = apicid;
mpc->mpc_apicver = apicver;
mpc->mpc_cpuflag = cpuflag;
mpc->mpc_cpufeature = cpufeature;
mpc->mpc_featureflag = featureflag;
smp_add_mpc_entry(mc, sizeof(*mpc));
}
/* If we assume a symmetric processor configuration we can
* get all of the information we need to write the processor
* entry from the bootstrap processor.
* Plus I don't think linux really even cares.
* Having the proper apicid's in the table so the non-bootstrap
* processors can be woken up should be enough.
*/
void smp_write_processors(struct mp_config_table *mc,
unsigned long *processor_map)
{
int i;
int processor_id;
unsigned apic_version;
unsigned cpu_features;
unsigned cpu_feature_flags;
int eax, ebx, ecx, edx;
processor_id = this_processors_id();
apic_version = apic_read(APIC_LVR) & 0xff;
cpuid(1, &eax, &ebx, &ecx, &edx);
cpu_features = eax;
cpu_feature_flags = edx;
for(i = 0; i < MAX_CPUS; i++) {
unsigned long cpu_apicid = initial_apicid[i];
unsigned long cpu_flag;
if(initial_apicid[i]==-1)
continue;
cpu_flag = MPC_CPU_ENABLED
if (processor_map[i] & CPU_BOOTPROCESSOR) {
cpu_flag |= MPC_CPU_BOOTPROCESSOR;
}
smp_write_processor(mc, cpu_apicid, apic_version,
cpu_flag, cpu_features, cpu_feature_flags
);
}
}
void smp_write_bus(struct mp_config_table *mc,
unsigned char id, unsigned char *bustype)
{
struct mpc_config_bus *mpc;
mpc = smp_next_mpc_entry(mc);
memset(mpc, '\0', sizeof(*mpc));
mpc->mpc_type = MP_BUS;
mpc->mpc_busid = id;
memcpy(mpc->mpc_bustype, bustype, sizeof(mpc->mpc_bustype));
smp_add_mpc_entry(mc, sizeof(*mpc));
}
void smp_write_ioapic(struct mp_config_table *mc,
unsigned char id, unsigned char ver,
unsigned long apicaddr)
{
struct mpc_config_ioapic *mpc;
mpc = smp_next_mpc_entry(mc);
memset(mpc, '\0', sizeof(*mpc));
mpc->mpc_type = MP_IOAPIC;
mpc->mpc_apicid = id;
mpc->mpc_apicver = ver;
mpc->mpc_flags = MPC_APIC_USABLE;
mpc->mpc_apicaddr = apicaddr;
smp_add_mpc_entry(mc, sizeof(*mpc));
}
void smp_write_intsrc(struct mp_config_table *mc,
unsigned char irqtype, unsigned short irqflag,
unsigned char srcbus, unsigned char srcbusirq,
unsigned char dstapic, unsigned char dstirq)
{
struct mpc_config_intsrc *mpc;
mpc = smp_next_mpc_entry(mc);
memset(mpc, '\0', sizeof(*mpc));
mpc->mpc_type = MP_INTSRC;
mpc->mpc_irqtype = irqtype;
mpc->mpc_irqflag = irqflag;
mpc->mpc_srcbus = srcbus;
mpc->mpc_srcbusirq = srcbusirq;
mpc->mpc_dstapic = dstapic;
mpc->mpc_dstirq = dstirq;
smp_add_mpc_entry(mc, sizeof(*mpc));
#if CONFIG_DEBUG_MPTABLE == 1
printk_info("add intsrc srcbus 0x%x srcbusirq 0x%x, dstapic 0x%x, dstirq 0x%x\n",
srcbus, srcbusirq, dstapic, dstirq);
hexdump(__FUNCTION__, mpc, sizeof(*mpc));
#endif
}
void smp_write_lintsrc(struct mp_config_table *mc,
unsigned char irqtype, unsigned short irqflag,
unsigned char srcbusid, unsigned char srcbusirq,
unsigned char destapic, unsigned char destapiclint)
{
struct mpc_config_lintsrc *mpc;
mpc = smp_next_mpc_entry(mc);
memset(mpc, '\0', sizeof(*mpc));
mpc->mpc_type = MP_LINTSRC;
mpc->mpc_irqtype = irqtype;
mpc->mpc_irqflag = irqflag;
mpc->mpc_srcbusid = srcbusid;
mpc->mpc_srcbusirq = srcbusirq;
mpc->mpc_destapic = destapic;
mpc->mpc_destapiclint = destapiclint;
smp_add_mpc_entry(mc, sizeof(*mpc));
}
void smp_write_address_space(struct mp_config_table *mc,
unsigned char busid, unsigned char address_type,
unsigned int address_base_low, unsigned int address_base_high,
unsigned int address_length_low, unsigned int address_length_high)
{
struct mp_exten_system_address_space *mpe;
mpe = smp_next_mpe_entry(mc);
memset(mpe, '\0', sizeof(*mpe));
mpe->mpe_type = MPE_SYSTEM_ADDRESS_SPACE;
mpe->mpe_length = sizeof(*mpe);
mpe->mpe_busid = busid;
mpe->mpe_address_type = address_type;
mpe->mpe_address_base_low = address_base_low;
mpe->mpe_address_base_high = address_base_high;
mpe->mpe_address_length_low = address_length_low;
mpe->mpe_address_length_high = address_length_high;
smp_add_mpe_entry(mc, (mpe_t)mpe);
}
void smp_write_bus_hierarchy(struct mp_config_table *mc,
unsigned char busid, unsigned char bus_info,
unsigned char parent_busid)
{
struct mp_exten_bus_hierarchy *mpe;
mpe = smp_next_mpe_entry(mc);
memset(mpe, '\0', sizeof(*mpe));
mpe->mpe_type = MPE_BUS_HIERARCHY;
mpe->mpe_length = sizeof(*mpe);
mpe->mpe_busid = busid;
mpe->mpe_bus_info = bus_info;
mpe->mpe_parent_busid = parent_busid;
smp_add_mpe_entry(mc, (mpe_t)mpe);
}
void smp_write_compatibility_address_space(struct mp_config_table *mc,
unsigned char busid, unsigned char address_modifier,
unsigned int range_list)
{
struct mp_exten_compatibility_address_space *mpe;
mpe = smp_next_mpe_entry(mc);
memset(mpe, '\0', sizeof(*mpe));
mpe->mpe_type = MPE_COMPATIBILITY_ADDRESS_SPACE;
mpe->mpe_length = sizeof(*mpe);
mpe->mpe_busid = busid;
mpe->mpe_address_modifier = address_modifier;
mpe->mpe_range_list = range_list;
smp_add_mpe_entry(mc, (mpe_t)mpe);
}

663
src/boot/elfboot.c Normal file
View File

@ -0,0 +1,663 @@
#include <console/console.h>
#include <part/fallback_boot.h>
#include <boot/elf.h>
#include <boot/elf_boot.h>
#include <boot/linuxbios_tables.h>
#include <ip_checksum.h>
#include <stream/read_bytes.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
/* Maximum physical address we can use for the linuxBIOS bounce buffer.
*/
#ifndef MAX_ADDR
#define MAX_ADDR -1UL
#endif
extern unsigned char _ram_seg;
extern unsigned char _eram_seg;
struct segment {
struct segment *next;
struct segment *prev;
struct segment *phdr_next;
struct segment *phdr_prev;
unsigned long s_addr;
unsigned long s_memsz;
unsigned long s_offset;
unsigned long s_filesz;
};
struct verify_callback {
struct verify_callback *next;
int (*callback)(struct verify_callback *vcb,
Elf_ehdr *ehdr, Elf_phdr *phdr, struct segment *head);
unsigned long desc_offset;
unsigned long desc_addr;
};
struct ip_checksum_vcb {
struct verify_callback data;
unsigned short ip_checksum;
};
int verify_ip_checksum(
struct verify_callback *vcb,
Elf_ehdr *ehdr, Elf_phdr *phdr, struct segment *head)
{
struct ip_checksum_vcb *cb;
struct segment *ptr;
unsigned long bytes;
unsigned long checksum;
unsigned char buff[2], *n_desc;
cb = (struct ip_checksum_vcb *)vcb;
/* zero the checksum so it's value won't
* get in the way of verifying the checksum.
*/
n_desc = 0;
if (vcb->desc_addr) {
n_desc = (unsigned char *)(vcb->desc_addr);
memcpy(buff, n_desc, 2);
memset(n_desc, 0, 2);
}
bytes = 0;
checksum = compute_ip_checksum(ehdr, sizeof(*ehdr));
bytes += sizeof(*ehdr);
checksum = add_ip_checksums(bytes, checksum,
compute_ip_checksum(phdr, ehdr->e_phnum*sizeof(*phdr)));
bytes += ehdr->e_phnum*sizeof(*phdr);
for(ptr = head->phdr_next; ptr != head; ptr = ptr->phdr_next) {
checksum = add_ip_checksums(bytes, checksum,
compute_ip_checksum((void *)ptr->s_addr, ptr->s_memsz));
bytes += ptr->s_memsz;
}
if (n_desc != 0) {
memcpy(n_desc, buff, 2);
}
if (checksum != cb->ip_checksum) {
printk_err("Image checksum: %04x != computed checksum: %04x\n",
cb->ip_checksum, checksum);
}
return checksum == cb->ip_checksum;
}
/* The problem:
* Static executables all want to share the same addresses
* in memory because only a few addresses are reliably present on
* a machine, and implementing general relocation is hard.
*
* The solution:
* - Allocate a buffer twice the size of the linuxBIOS image.
* - Anything that would overwrite linuxBIOS copy into the lower half of
* the buffer.
* - After loading an ELF image copy linuxBIOS to the upper half of the
* buffer.
* - Then jump to the loaded image.
*
* Benefits:
* - Nearly arbitrary standalone executables can be loaded.
* - LinuxBIOS is preserved, so it can be returned to.
* - The implementation is still relatively simple,
* and much simpler then the general case implemented in kexec.
*
*/
static unsigned long get_bounce_buffer(struct lb_memory *mem)
{
unsigned long lb_size;
unsigned long mem_entries;
unsigned long buffer;
int i;
lb_size = (unsigned long)(&_eram_seg - &_ram_seg);
/* Double linuxBIOS size so I have somewhere to place a copy to return to */
lb_size = lb_size + lb_size;
mem_entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
buffer = 0;
for(i = 0; i < mem_entries; i++) {
unsigned long mstart, mend;
unsigned long msize;
unsigned long tbuffer;
if (mem->map[i].type != LB_MEM_RAM)
continue;
if (mem->map[i].start > MAX_ADDR)
continue;
if (mem->map[i].size < lb_size)
continue;
mstart = mem->map[i].start;
msize = MAX_ADDR - mstart +1;
if (msize > mem->map[i].size)
msize = mem->map[i].size;
mend = mstart + msize;
tbuffer = mend - lb_size;
if (tbuffer < buffer)
continue;
buffer = tbuffer;
}
return buffer;
}
static struct verify_callback *process_elf_notes(
unsigned char *header,
unsigned long offset, unsigned long length)
{
struct verify_callback *cb_chain;
unsigned char *note, *end;
char *program, *version;
cb_chain = 0;
note = header + offset;
end = note + length;
program = version = 0;
while(note < end) {
Elf_Nhdr *hdr;
unsigned char *n_name, *n_desc, *next;
hdr = (Elf_Nhdr *)note;
n_name = note + sizeof(*hdr);
n_desc = n_name + ((hdr->n_namesz + 3) & ~3);
next = n_desc + ((hdr->n_descsz + 3) & ~3);
if (next > end) {
break;
}
if ((hdr->n_namesz == sizeof(ELF_NOTE_BOOT)) &&
(memcmp(n_name, ELF_NOTE_BOOT, sizeof(ELF_NOTE_BOOT)) == 0)) {
switch(hdr->n_type) {
case EIN_PROGRAM_NAME:
if (n_desc[hdr->n_descsz -1] == 0) {
program = n_desc;
}
break;
case EIN_PROGRAM_VERSION:
if (n_desc[hdr->n_descsz -1] == 0) {
version = n_desc;
}
break;
case EIN_PROGRAM_CHECKSUM:
{
struct ip_checksum_vcb *cb;
cb = malloc(sizeof(*cb));
cb->ip_checksum = *((uint16_t *)n_desc);
cb->data.callback = verify_ip_checksum;
cb->data.next = cb_chain;
cb->data.desc_offset = n_desc - header;
cb_chain = &cb->data;
break;
}
}
}
printk_spew("n_type: %08x n_name(%d): %-*.*s n_desc(%d): %-*.*s\n",
hdr->n_type,
hdr->n_namesz, hdr->n_namesz, hdr->n_namesz, n_name,
hdr->n_descsz,hdr->n_descsz, hdr->n_descsz, n_desc);
note = next;
}
if (program && version) {
printk_info("Loading %s version: %s\n",
program, version);
}
return cb_chain;
}
static int valid_area(struct lb_memory *mem, unsigned long buffer,
unsigned long start, unsigned long len)
{
/* Check through all of the memory segments and ensure
* the segment that was passed in is completely contained
* in RAM.
*/
int i;
unsigned long end = start + len;
unsigned long mem_entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
/* See if I conflict with the bounce buffer */
if (end >= buffer) {
return 0;
}
/* Walk through the table of valid memory ranges and see if I
* have a match.
*/
for(i = 0; i < mem_entries; i++) {
uint64_t mstart, mend;
uint32_t mtype;
mtype = mem->map[i].type;
mstart = mem->map[i].start;
mend = mstart + mem->map[i].size;
if ((mtype == LB_MEM_RAM) && (start < mend) && (end > mstart)) {
break;
}
}
if (i == mem_entries) {
printk_err("No matching ram area found for range:\n");
printk_err(" [0x%016lx, 0x%016lx)\n", start, end);
printk_err("Ram areas\n");
for(i = 0; i < mem_entries; i++) {
uint64_t mstart, mend;
uint32_t mtype;
mtype = mem->map[i].type;
mstart = mem->map[i].start;
mend = mstart + mem->map[i].size;
printk_err(" [0x%016lx, 0x%016lx) %s\n",
(unsigned long)mstart,
(unsigned long)mend,
(mtype == LB_MEM_RAM)?"RAM":"Reserved");
}
return 0;
}
return 1;
}
static void relocate_segment(unsigned long buffer, struct segment *seg)
{
/* Modify all segments that want to load onto linuxBIOS
* to load onto the bounce buffer instead.
*/
unsigned long lb_start = (unsigned long)&_ram_seg;
unsigned long lb_end = (unsigned long)&_eram_seg;
unsigned long start, middle, end;
printk_spew("lb: [0x%016lx, 0x%016lx)\n",
lb_start, lb_end);
start = seg->s_addr;
middle = start + seg->s_filesz;
end = start + seg->s_memsz;
/* I don't conflict with linuxBIOS so get out of here */
if ((end <= lb_start) || (start >= lb_end))
return;
printk_spew("segment: [0x%016lx, 0x%016lx, 0x%016lx)\n",
start, middle, end);
/* Slice off a piece at the beginning
* that doesn't conflict with linuxBIOS.
*/
if (start < lb_start) {
struct segment *new;
unsigned long len = lb_start - start;
new = malloc(sizeof(*new));
*new = *seg;
new->s_memsz = len;
seg->s_memsz -= len;
seg->s_addr += len;
seg->s_offset += len;
if (seg->s_filesz > len) {
new->s_filesz = len;
seg->s_filesz -= len;
} else {
seg->s_filesz = 0;
}
/* Order by stream offset */
new->next = seg;
new->prev = seg->prev;
seg->prev->next = new;
seg->prev = new;
/* Order by original program header order */
new->phdr_next = seg;
new->phdr_prev = seg->phdr_prev;
seg->phdr_prev->phdr_next = new;
seg->phdr_prev = new;
/* compute the new value of start */
start = seg->s_addr;
printk_spew(" early: [0x%016lx, 0x%016lx, 0x%016lx)\n",
new->s_addr,
new->s_addr + new->s_filesz,
new->s_addr + new->s_memsz);
}
/* Slice off a piece at the end
* that doesn't conflict with linuxBIOS
*/
if (end > lb_end) {
unsigned long len = lb_end - start;
struct segment *new;
new = malloc(sizeof(*new));
*new = *seg;
seg->s_memsz = len;
new->s_memsz -= len;
new->s_addr += len;
new->s_offset += len;
if (seg->s_filesz > len) {
seg->s_filesz = len;
new->s_filesz -= len;
} else {
new->s_filesz = 0;
}
/* Order by stream offset */
new->next = seg->next;
new->prev = seg;
seg->next->prev = new;
seg->next = new;
/* Order by original program header order */
new->phdr_next = seg->phdr_next;
new->phdr_prev = seg;
seg->phdr_next->phdr_prev = new;
seg->phdr_next = new;
/* compute the new value of end */
end = start + len;
printk_spew(" late: [0x%016lx, 0x%016lx, 0x%016lx)\n",
new->s_addr,
new->s_addr + new->s_filesz,
new->s_addr + new->s_memsz);
}
/* Now retarget this segment onto the bounce buffer */
seg->s_addr = buffer + (seg->s_addr - lb_start);
printk_spew(" bounce: [0x%016lx, 0x%016lx, 0x%016lx)\n",
seg->s_addr,
seg->s_addr + seg->s_filesz,
seg->s_addr + seg->s_memsz);
}
static int build_elf_segment_list(
struct segment *head,
unsigned long bounce_buffer, struct lb_memory *mem,
Elf_phdr *phdr, int headers)
{
struct segment *ptr;
int i;
memset(head, 0, sizeof(*head));
head->next = head->prev = head;
for(i = 0; i < headers; i++) {
struct segment *new;
/* Ignore data that I don't need to handle */
if (phdr[i].p_type != PT_LOAD) {
printk_debug("Dropping non PT_LOAD segment\n");
continue;
}
if (phdr[i].p_memsz == 0) {
printk_debug("Dropping empty segment\n");
continue;
}
new = malloc(sizeof(*new));
new->s_addr = phdr[i].p_paddr;
new->s_memsz = phdr[i].p_memsz;
new->s_offset = phdr[i].p_offset;
new->s_filesz = phdr[i].p_filesz;
printk_debug("New segment addr 0x%lx size 0x%lx offset 0x%lx filesize 0x%lx\n",
new->s_addr, new->s_memsz, new->s_offset, new->s_filesz);
/* Clean up the values */
if (new->s_filesz > new->s_memsz) {
new->s_filesz = new->s_memsz;
}
printk_debug("(cleaned up) New segment addr 0x%lx size 0x%lx offset 0x%lx filesize 0x%lx\n",
new->s_addr, new->s_memsz, new->s_offset, new->s_filesz);
for(ptr = head->next; ptr != head; ptr = ptr->next) {
if (new->s_offset < ptr->s_offset)
break;
}
/* Order by stream offset */
new->next = ptr;
new->prev = ptr->prev;
ptr->prev->next = new;
ptr->prev = new;
/* Order by original program header order */
new->phdr_next = head;
new->phdr_prev = head->phdr_prev;
head->phdr_prev->phdr_next = new;
head->phdr_prev = new;
/* Verify the memory addresses in the segment are valid */
if (!valid_area(mem, bounce_buffer, new->s_addr, new->s_memsz))
goto out;
/* Modify the segment to load onto the bounce_buffer if necessary.
*/
relocate_segment(bounce_buffer, new);
}
return 1;
out:
return 0;
}
static int load_elf_segments(
struct segment *head, unsigned char *header, unsigned long header_size)
{
unsigned long offset;
struct segment *ptr;
offset = 0;
for(ptr = head->next; ptr != head; ptr = ptr->next) {
unsigned long start_offset;
unsigned long skip_bytes, read_bytes;
unsigned char *dest, *middle, *end;
byte_offset_t result;
printk_debug("Loading Segment: addr: 0x%016lx memsz: 0x%016lx filesz: 0x%016lx\n",
ptr->s_addr, ptr->s_memsz, ptr->s_filesz);
/* Compute the boundaries of the segment */
dest = (unsigned char *)(ptr->s_addr);
end = dest + ptr->s_memsz;
middle = dest + ptr->s_filesz;
start_offset = ptr->s_offset;
printk_spew("[ 0x%016lx, %016lx, 0x%016lx) <- %016lx\n",
(unsigned long)dest,
(unsigned long)middle,
(unsigned long)end,
(unsigned long)start_offset);
/* Skip intial buffer unused bytes */
if (offset < header_size) {
if (start_offset < header_size) {
offset = start_offset;
} else {
offset = header_size;
}
}
/* Skip the unused bytes */
skip_bytes = start_offset - offset;
if (skip_bytes &&
((result = stream_skip(skip_bytes)) != skip_bytes)) {
printk_err("ERROR: Skip of %ld bytes skiped %ld bytes\n",
skip_bytes, result);
goto out;
}
offset = start_offset;
/* Copy data from the initial buffer */
if (offset < header_size) {
size_t len;
if ((ptr->s_filesz + start_offset) > header_size) {
len = header_size - start_offset;
}
else {
len = ptr->s_filesz;
}
memcpy(dest, &header[start_offset], len);
dest += len;
}
/* Read the segment into memory */
read_bytes = middle - dest;
if (read_bytes &&
((result = stream_read(dest, read_bytes)) != read_bytes)) {
printk_err("ERROR: Read of %ld bytes read %ld bytes...\n",
read_bytes, result);
goto out;
}
offset += ptr->s_filesz;
/* Zero the extra bytes between middle & end */
if (middle < end) {
printk_debug("Clearing Segment: addr: 0x%016lx memsz: 0x%016lx\n",
(unsigned long)middle, end - middle);
/* Zero the extra bytes */
memset(middle, 0, end - middle);
}
}
return 1;
out:
return 0;
}
static int verify_loaded_image(
struct verify_callback *vcb,
Elf_ehdr *ehdr, Elf_phdr *phdr,
struct segment *head
)
{
struct segment *ptr;
int ok;
ok = 1;
for(; ok && vcb ; vcb = vcb->next) {
/* Find where the note is loaded */
/* The whole note must be loaded intact
* so an address of 0 for the descriptor is impossible
*/
vcb->desc_addr = 0;
for(ptr = head->next; ptr != head; ptr = ptr->next) {
unsigned long desc_addr;
desc_addr = ptr->s_addr + vcb->desc_offset - ptr->s_offset;
if ((desc_addr >= ptr->s_addr) &&
(desc_addr < (ptr->s_addr + ptr->s_filesz))) {
vcb->desc_addr = desc_addr;
}
}
ok = vcb->callback(vcb, ehdr, phdr, head);
}
return ok;
}
int elfload(struct lb_memory *mem,
unsigned char *header, unsigned long header_size)
{
Elf_ehdr *ehdr;
Elf_phdr *phdr;
void *entry;
struct segment head;
struct verify_callback *cb_chain;
unsigned long bounce_buffer;
/* Find a bounce buffer so I can load to linuxBIOS's current location */
bounce_buffer = get_bounce_buffer(mem);
if (!bounce_buffer) {
printk_err("Could not find a bounce buffer...\n");
goto out;
}
ehdr = (Elf_ehdr *)header;
entry = (void *)(ehdr->e_entry);
phdr = (Elf_phdr *)(&header[ehdr->e_phoff]);
/* Digest elf note information... */
cb_chain = 0;
if ((phdr[0].p_type == PT_NOTE) &&
((phdr[0].p_offset + phdr[0].p_filesz) < header_size)) {
cb_chain = process_elf_notes(header,
phdr[0].p_offset, phdr[0].p_filesz);
}
/* Preprocess the elf segments */
if (!build_elf_segment_list(&head,
bounce_buffer, mem, phdr, ehdr->e_phnum))
goto out;
/* Load the segments */
if (!load_elf_segments(&head, header, header_size))
goto out;
printk_spew("Loaded segments\n");
/* Verify the loaded image */
if (!verify_loaded_image(cb_chain, ehdr, phdr, &head))
goto out;
printk_spew("verified segments\n");
/* Shutdown the stream device */
stream_fini();
printk_spew("closed down stream\n");
/* Reset to booting from this image as late as possible */
boot_successful();
printk_debug("Jumping to boot code at 0x%x\n", entry);
post_code(0xfe);
/* Jump to kernel */
jmp_to_elf_entry(entry, bounce_buffer);
return 1;
out:
return 0;
}
int elfboot(struct lb_memory *mem)
{
Elf_ehdr *ehdr;
static unsigned char header[ELF_HEAD_SIZE];
int header_offset;
int i, result;
result = 0;
printk_info("\n");
printk_info("Welcome to %s, the open sourced starter.\n", BOOTLOADER);
printk_info("January 2002, Eric Biederman.\n");
printk_info("Version %s\n", BOOTLOADER_VERSION);
printk_info("\n");
post_code(0xf8);
if (stream_init() < 0) {
printk_err("Could not initialize driver...\n");
goto out;
}
/* Read in the initial ELF_HEAD_SIZE bytes */
if (stream_read(header, ELF_HEAD_SIZE) != ELF_HEAD_SIZE) {
printk_err("Read failed...\n");
goto out;
}
/* Scan for an elf header */
header_offset = -1;
for(i = 0; i < ELF_HEAD_SIZE - (sizeof(Elf_ehdr) + sizeof(Elf_phdr)); i+=16) {
ehdr = (Elf_ehdr *)(&header[i]);
if (memcmp(ehdr->e_ident, ELFMAG, 4) != 0) {
printk_spew("NO header at %d\n", i);
continue;
}
printk_debug("Found ELF candiate at offset %d\n", i);
/* Sanity check the elf header */
if ((ehdr->e_type == ET_EXEC) &&
elf_check_arch(ehdr) &&
(ehdr->e_ident[EI_VERSION] == EV_CURRENT) &&
(ehdr->e_version == EV_CURRENT) &&
(ehdr->e_ehsize == sizeof(Elf_ehdr)) &&
(ehdr->e_phentsize = sizeof(Elf_phdr)) &&
(ehdr->e_phoff < (ELF_HEAD_SIZE - i)) &&
((ehdr->e_phoff + (ehdr->e_phentsize * ehdr->e_phnum)) <=
(ELF_HEAD_SIZE - i))) {
header_offset = i;
break;
}
ehdr = 0;
}
printk_spew("header_offset is %d\n", header_offset);
if (header_offset == -1) {
goto out;
}
printk_spew("Try to load at offset 0x%x\n", header_offset);
result = elfload(mem,
header + header_offset , ELF_HEAD_SIZE - header_offset);
out:
if (!result) {
/* Shutdown the stream device */
stream_fini();
printk_err("Cannot Load ELF Image\n");
post_code(0xff);
}
return 0;
}

216
src/boot/hardwaremain.c Normal file
View File

@ -0,0 +1,216 @@
/*
This software and ancillary information (herein called SOFTWARE )
called LinuxBIOS is made available under the terms described
here. The SOFTWARE has been approved for release with associated
LA-CC Number 00-34 . Unless otherwise indicated, this SOFTWARE has
been authored by an employee or employees of the University of
California, operator of the Los Alamos National Laboratory under
Contract No. W-7405-ENG-36 with the U.S. Department of Energy. The
U.S. Government has rights to use, reproduce, and distribute this
SOFTWARE. The public may copy, distribute, prepare derivative works
and publicly display this SOFTWARE without charge, provided that this
Notice and any statement of authorship are reproduced on all copies.
Neither the Government nor the University makes any warranty, express
or implied, or assumes any liability or responsibility for the use of
this SOFTWARE. If SOFTWARE is modified to produce derivative works,
such modified SOFTWARE should be clearly marked, so as not to confuse
it with the version available from LANL.
*/
/* Copyright 2000, Ron Minnich, Advanced Computing Lab, LANL
* rminnich@lanl.gov
*/
/*
* C Bootstrap code for the LinuxBIOS
*/
#include <console/console.h>
#include <cpu/cpu.h>
#include <mem.h>
#include <version.h>
#include <smp/start_stop.h>
#include <boot/tables.h>
#include <part/sizeram.h>
#include <device.h>
#include <pci.h>
#if 0
#include <part/mainboard.h>
#endif
#if 0
#include <part/hard_reset.h>
#endif
#include <smp/atomic.h>
#include <boot/elf.h>
#ifndef CONFIG_MAX_PHYSICAL_CPUS
#define CONFIG_MAX_PHYSICAL_CPUS CONFIG_MAX_CPUS
#endif
/* The processor map.
* Now that SMP is in linuxbios, and Linux counts on us
* giving accurate information about processors, we need a map
* of what processors are out there. This could be a bit mask,
* but we will be optimistic and hope we someday run on
* REALLY BIG SMPs. Also we may need more than one bit of
* info per processor at some point. I hope we don't need
* anything more complex than an int.
*/
static unsigned long processor_map[MAX_CPUS];
static struct mem_range *get_ramsize(void)
{
struct mem_range *mem = 0;
if (!mem) {
mem = sizeram();
}
if (!mem) {
printk_err("No memory size information!\n");
for(;;);
}
return mem;
}
#if SMP == 1
/* Number of cpus that are currently running in linuxbios */
static atomic_t active_cpus = ATOMIC_INIT(1);
void secondary_cpu_init(void)
{
struct mem_range *mem;
unsigned long id;
int index;
atomic_inc(&active_cpus);
printk_debug(__FUNCTION__ "\n");
mem = get_ramsize();
id = cpu_initialize(mem);
index = processor_index(id);
printk_debug(__FUNCTION__ " %d/%u\n", index, id);
processor_map[index] = CPU_ENABLED;
atomic_dec(&active_cpus);
stop_cpu(id);
}
static void wait_for_other_cpus(void)
{
int old_active_count, active_count;
int i;
old_active_count = 1;
active_count = atomic_read(&active_cpus);
while(active_count > 1) {
if (active_count != old_active_count) {
printk_info("Waiting for %d CPUS to stop\n", active_count);
old_active_count = active_count;
}
active_count = atomic_read(&active_cpus);
}
for(i = 0; i < MAX_CPUS; i++) {
if (!(processor_map[i] & CPU_ENABLED)) {
printk_err("CPU %d/%u did not initialize!\n",
i, initial_apicid[i]);
processor_map[i] = 0;
mainboard_cpu_fixup(i);
}
}
printk_debug("All AP CPUs stopped\n");
}
#else /* SMP */
#define wait_for_other_cpus() do {} while(0)
#endif /* SMP */
void hardwaremain(int boot_complete)
{
/* Processor ID of the BOOT cpu (i.e. the one running this code) */
unsigned long boot_cpu;
int boot_index;
/* the order here is a bit tricky. We don't want to do much of
* anything that uses config registers until after PciAllocateResources
* since that function also figures out what kind of config strategy
* to use (type 1 or type 2).
* so we turn on cache, then worry about PCI setup, then do other
* things, so that the other work can use the PciRead* and PciWrite*
* functions.
*/
struct mem_range *mem, *tmem;
struct lb_memory *lb_mem;
unsigned long totalmem;
post_code(0x80);
/* displayinit MUST PRECEDE ALL PRINTK! */
console_init();
post_code(0x39);
printk_notice("LinuxBIOS-%s%s %s %s...\n",
linuxbios_version, linuxbios_extra_version, linuxbios_build,
(boot_complete)?"rebooting":"booting");
post_code(0x40);
#if 0
/* If we have already booted attempt a hard reboot */
if (boot_complete) {
hard_reset();
}
#endif
#if 1
// pick how to scan the bus. This is first so we can get at memory size.
printk_info("Finding PCI configuration type.\n");
pci_set_method();
post_code(0x5f);
#if 0
enumerate_static_devices();
#endif
dev_enumerate();
post_code(0x66);
// Now do the real bus
// we round the total ram up a lot for thing like the SISFB, which
// shares high memory with the CPU.
dev_configure();
post_code(0x88);
dev_enable();
dev_initialize();
post_code(0x89);
#endif
mem = get_ramsize();
post_code(0x70);
totalmem = 0;
for(tmem = mem; tmem->sizek; tmem++) {
totalmem += tmem->sizek;
}
printk_info("totalram: %ldM\n",
(totalmem + 512) >> 10); /* Round to the nearest meg */
/* Fully initialize the cpu before configuring the bus */
boot_cpu = cpu_initialize(mem);
boot_index = processor_index(boot_cpu);
printk_spew("BOOT CPU is %d\n", boot_cpu);
processor_map[boot_index] = CPU_BOOTPROCESSOR|CPU_ENABLED;
/* Now start the other cpus initializing
* The sooner they start the sooner they stop.
*/
post_code(0x75);
startup_other_cpus(processor_map);
post_code(0x77);
/* make certain we are the only cpu running in linuxBIOS */
wait_for_other_cpus();
/* Now that we have collected all of our information
* write our configuration tables.
*/
lb_mem = write_tables(mem, processor_map);
elfboot(lb_mem);
}

691
src/config/LinuxBIOSDoc.config Executable file
View File

@ -0,0 +1,691 @@
# Doxyfile 1.2.1
# This file describes the settings to be used by doxygen for a project
#
# All text after a hash (#) is considered a comment and will be ignored
# The format is:
# TAG = value [value, ...]
# For lists items can also be appended using:
# TAG += value [value, ...]
# Values that contain spaces should be placed between quotes (" ")
#---------------------------------------------------------------------------
# General configuration options
#---------------------------------------------------------------------------
# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
# by quotes) that should identify the project.
PROJECT_NAME = "LinuxBIOS"
# The PROJECT_NUMBER tag can be used to enter a project or revision number.
# This could be handy for archiving the generated documentation or
# if some version control system is used.
PROJECT_NUMBER =
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.
# If a relative path is entered, it will be relative to the location
# where doxygen was started. If left blank the current directory will be used.
OUTPUT_DIRECTORY = .
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
# documentation generated by doxygen is written. Doxygen will use this
# information to generate all constant output in the proper language.
# The default language is English, other supported languages are:
# Dutch, French, Italian, Czech, Swedish, German, Finnish, Japanese,
# Spanish, Russian, Croatian, Polish, and Portuguese.
OUTPUT_LANGUAGE = English
# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
# documentation are documented, even if no documentation was available.
# Private class members and static file members will be hidden unless
# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
EXTRACT_ALL = YES
# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
# will be included in the documentation.
EXTRACT_PRIVATE = YES
# If the EXTRACT_STATIC tag is set to YES all static members of a file
# will be included in the documentation.
EXTRACT_STATIC = YES
# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
# undocumented members of documented classes, files or namespaces.
# If set to NO (the default) these members will be included in the
# various overviews, but no documentation section is generated.
# This option has no effect if EXTRACT_ALL is enabled.
HIDE_UNDOC_MEMBERS = NO
# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
# undocumented classes that are normally visible in the class hierarchy.
# If set to NO (the default) these class will be included in the various
# overviews. This option has no effect if EXTRACT_ALL is enabled.
HIDE_UNDOC_CLASSES = NO
# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
# include brief member descriptions after the members that are listed in
# the file and class documentation (similar to JavaDoc).
# Set to NO to disable this.
BRIEF_MEMBER_DESC = YES
# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
# the brief description of a member or function before the detailed description.
# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
# brief descriptions will be completely suppressed.
REPEAT_BRIEF = YES
# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
# Doxygen will generate a detailed section even if there is only a brief
# description.
ALWAYS_DETAILED_SEC = NO
# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
# path before files name in the file list and in the header files. If set
# to NO the shortest path that makes the file name unique will be used.
FULL_PATH_NAMES = NO
# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
# can be used to strip a user defined part of the path. Stripping is
# only done if one of the specified strings matches the left-hand part of
# the path. It is allowed to use relative paths in the argument list.
STRIP_FROM_PATH =
# The INTERNAL_DOCS tag determines if documentation
# that is typed after a \internal command is included. If the tag is set
# to NO (the default) then the documentation will be excluded.
# Set it to YES to include the internal documentation.
INTERNAL_DOCS = NO
# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
# generate a class diagram (in Html and LaTeX) for classes with base or
# super classes. Setting the tag to NO turns the diagrams off.
CLASS_DIAGRAMS = YES
# If the SOURCE_BROWSER tag is set to YES then a list of source files will
# be generated. Documented entities will be cross-referenced with these sources.
SOURCE_BROWSER = YES
# Setting the INLINE_SOURCES tag to YES will include the body
# of functions and classes directly in the documentation.
INLINE_SOURCES = NO
# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
# doxygen to hide any special comment blocks from generated source code
# fragments. Normal C and C++ comments will always remain visible.
STRIP_CODE_COMMENTS = YES
# If the CASE_SENSE_NAMES tag is set to NO (the default) then Doxygen
# will only generate file names in lower case letters. If set to
# YES upper case letters are also allowed. This is useful if you have
# classes or files whose names only differ in case and if your file system
# supports case sensitive file names.
CASE_SENSE_NAMES = YES
# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
# will show members with their full class and namespace scopes in the
# documentation. If set to YES the scope will be hidden.
HIDE_SCOPE_NAMES = NO
# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
# will generate a verbatim copy of the header file for each class for
# which an include is specified. Set to NO to disable this.
VERBATIM_HEADERS = YES
# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
# will put list of the files that are included by a file in the documentation
# of that file.
SHOW_INCLUDE_FILES = YES
# If the JAVADOC_AUTOBRIEF tag is set to YES (the default) then Doxygen
# will interpret the first line (until the first dot) of a JavaDoc-style
# comment as the brief description. If set to NO, the Javadoc-style will
# behave just like the Qt-style comments.
JAVADOC_AUTOBRIEF = YES
# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
# member inherits the documentation from any documented member that it
# reimplements.
INHERIT_DOCS = YES
# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
# is inserted in the documentation for inline members.
INLINE_INFO = YES
# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
# will sort the (detailed) documentation of file and class members
# alphabetically by member name. If set to NO the members will appear in
# declaration order.
SORT_MEMBER_DOCS = YES
# The TAB_SIZE tag can be used to set the number of spaces in a tab.
# Doxygen uses this value to replace tabs by spaces in code fragments.
TAB_SIZE = 8
# The ENABLE_SECTIONS tag can be used to enable conditional
# documentation sections, marked by \if sectionname ... \endif.
ENABLED_SECTIONS =
# The GENERATE_TODOLIST tag can be used to enable (YES) or
# disable (NO) the todo list. This list is created by putting \todo
# commands in the documentation.
GENERATE_TODOLIST = YES
# The GENERATE_TESTLIST tag can be used to enable (YES) or
# disable (NO) the test list. This list is created by putting \test
# commands in the documentation.
GENERATE_TESTLIST = YES
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
# The QUIET tag can be used to turn on/off the messages that are generated
# by doxygen. Possible values are YES and NO. If left blank NO is used.
QUIET = NO
# The WARNINGS tag can be used to turn on/off the warning messages that are
# generated by doxygen. Possible values are YES and NO. If left blank
# NO is used.
WARNINGS = YES
# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
# automatically be disabled.
WARN_IF_UNDOCUMENTED = YES
# The WARN_FORMAT tag determines the format of the warning messages that
# doxygen can produce. The string should contain the $file, $line, and $text
# tags, which will be replaced by the file and line number from which the
# warning originated and the warning text.
WARN_FORMAT = "$file:$line: $text"
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
# The INPUT tag can be used to specify the files and/or directories that contain
# documented source files. You may enter file names like "myfile.cpp" or
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
# INPUT = ../src
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
# and *.h) to filter out the source-files in the directories. If left
# blank all files are included.
# FILE_PATTERNS = *.c *.h *.S
# The RECURSIVE tag can be used to turn specify whether or not subdirectories
# should be searched for input files as well. Possible values are YES and NO.
# If left blank NO is used.
RECURSIVE = YES
# The EXCLUDE tag can be used to specify files and/or directories that should
# excluded from the INPUT source files. This way you can easily exclude a
# subdirectory from a directory tree whose root is specified with the INPUT tag.
EXCLUDE =
# If the value of the INPUT tag contains directories, you can use the
# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
# certain files from those directories.
EXCLUDE_PATTERNS =
# The EXAMPLE_PATH tag can be used to specify one or more files or
# directories that contain example code fragments that are included (see
# the \include command).
EXAMPLE_PATH =
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
# and *.h) to filter out the source-files in the directories. If left
# blank all files are included.
EXAMPLE_PATTERNS =
# The IMAGE_PATH tag can be used to specify one or more files or
# directories that contain image that are included in the documentation (see
# the \image command).
IMAGE_PATH =
# The INPUT_FILTER tag can be used to specify a program that doxygen should
# invoke to filter for each input file. Doxygen will invoke the filter program
# by executing (via popen()) the command <filter> <input-file>, where <filter>
# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
# input file. Doxygen will then use the output that the filter program writes
# to standard output.
INPUT_FILTER =
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
# of all compounds will be generated. Enable this if the project
# contains a lot of classes, structs, unions or interfaces.
ALPHABETICAL_INDEX = NO
# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
# in which this list will be split (can be a number in the range [1..20])
COLS_IN_ALPHA_INDEX = 5
# In case all classes in a project start with a common prefix, all
# classes will be put under the same header in the alphabetical index.
# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
# should be ignored while generating the index headers.
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# configuration options related to the HTML output
#---------------------------------------------------------------------------
# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
# generate HTML output.
GENERATE_HTML = YES
# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `html' will be used as the default path.
HTML_OUTPUT = html
# The HTML_HEADER tag can be used to specify a personal HTML header for
# each generated HTML page. If it is left blank doxygen will generate a
# standard header.
HTML_HEADER =
# The HTML_FOOTER tag can be used to specify a personal HTML footer for
# each generated HTML page. If it is left blank doxygen will generate a
# standard footer.
HTML_FOOTER =
# The HTML_STYLESHEET tag can be used to specify a user defined cascading
# style sheet that is used by each HTML page. It can be used to
# fine-tune the look of the HTML output. If the tag is left blank doxygen
# will generate a default style sheet
HTML_STYLESHEET =
# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
# files or namespaces will be aligned in HTML using tables. If set to
# NO a bullet list will be used.
HTML_ALIGN_MEMBERS = YES
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
# will be generated that can be used as input for tools like the
# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
# of the generated HTML documentation.
GENERATE_HTMLHELP = NO
# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
# top of each HTML page. The value NO (the default) enables the index and
# the value YES disables it.
DISABLE_INDEX = NO
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
# generate Latex output.
GENERATE_LATEX = YES
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `latex' will be used as the default path.
LATEX_OUTPUT = latex
# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
# LaTeX documents. This may be useful for small projects and may help to
# save some trees in general.
COMPACT_LATEX = NO
# The PAPER_TYPE tag can be used to set the paper type that is used
# by the printer. Possible values are: a4, a4wide, letter, legal and
# executive. If left blank a4wide will be used.
PAPER_TYPE = a4wide
# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
# packages that should be included in the LaTeX output.
EXTRA_PACKAGES =
# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
# the generated latex document. The header should contain everything until
# the first chapter. If it is left blank doxygen will generate a
# standard header. Notice: only use this tag if you know what you are doing!
LATEX_HEADER =
# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
# is prepared for conversion to pdf (using ps2pdf). The pdf file will
# contain links (just like the HTML output) instead of page references
# This makes the output suitable for online browsing using a pdf viewer.
PDF_HYPERLINKS = NO
# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
# plain latex in the generated Makefile. Set this option to YES to get a
# higher quality PDF documentation.
USE_PDFLATEX = NO
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
# command to the generated LaTeX files. This will instruct LaTeX to keep
# running if errors occur, instead of asking the user for help.
# This option is also used when generating formulas in HTML.
LATEX_BATCHMODE = NO
#---------------------------------------------------------------------------
# configuration options related to the RTF output
#---------------------------------------------------------------------------
# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
# The RTF output is optimised for Word 97 and may not look very pretty with
# other RTF readers or editors.
GENERATE_RTF = YES
# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `rtf' will be used as the default path.
RTF_OUTPUT = rtf
# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
# RTF documents. This may be useful for small projects and may help to
# save some trees in general.
COMPACT_RTF = NO
# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
# will contain hyperlink fields. The RTF file will
# contain links (just like the HTML output) instead of page references.
# This makes the output suitable for online browsing using a WORD or other.
# programs which support those fields.
# Note: wordpad (write) and others do not support links.
RTF_HYPERLINKS = NO
# Load stylesheet definitions from file. Syntax is similar to doxygen's
# config file, i.e. a series of assigments. You only have to provide
# replacements, missing definitions are set to their default value.
RTF_STYLESHEET_FILE =
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
# generate man pages
GENERATE_MAN = YES
# The MAN_OUTPUT tag is used to specify where the man pages will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `man' will be used as the default path.
MAN_OUTPUT = man
# The MAN_EXTENSION tag determines the extension that is added to
# the generated man pages (default is the subroutine's section .3)
MAN_EXTENSION = .3
#---------------------------------------------------------------------------
# configuration options related to the XML output
#---------------------------------------------------------------------------
# If the GENERATE_XML tag is set to YES Doxygen will
# generate an XML file that captures the structure of
# the code including all documentation. Warning: This feature
# is still experimental and very incomplete.
GENERATE_XML = NO
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
# evaluate all C-preprocessor directives found in the sources and include
# files.
ENABLE_PREPROCESSING = YES
# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
# names in the source code. If set to NO (the default) only conditional
# compilation will be performed. Macro expansion can be done in a controlled
# way by setting EXPAND_ONLY_PREDEF to YES.
MACRO_EXPANSION = NO
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
# then the macro expansion is limited to the macros specified with the
# PREDEFINED and EXPAND_AS_PREDEFINED tags.
EXPAND_ONLY_PREDEF = NO
# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
# in the INCLUDE_PATH (see below) will be search if a #include is found.
SEARCH_INCLUDES = YES
# The INCLUDE_PATH tag can be used to specify one or more directories that
# contain include files that are not input files but should be processed by
# the preprocessor.
INCLUDE_PATH =
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
# patterns (like *.h and *.hpp) to filter out the header-files in the
# directories. If left blank, the patterns specified with FILE_PATTERNS will
# be used.
INCLUDE_FILE_PATTERNS =
# The PREDEFINED tag can be used to specify one or more macro names that
# are defined before the preprocessor is started (similar to the -D option of
# gcc). The argument of the tag is a list of macros of the form: name
# or name=definition (no spaces). If the definition and the = are
# omitted =1 is assumed.
PREDEFINED =
# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then
# this tag can be used to specify a list of macro names that should be expanded.
# The macro definition that is found in the sources will be used.
# Use the PREDEFINED tag if you want to use a different macro definition.
EXPAND_AS_DEFINED =
#---------------------------------------------------------------------------
# Configuration::addtions related to external references
#---------------------------------------------------------------------------
# The TAGFILES tag can be used to specify one or more tagfiles.
TAGFILES =
# When a file name is specified after GENERATE_TAGFILE, doxygen will create
# a tag file that is based on the input files it reads.
GENERATE_TAGFILE =
# If the ALLEXTERNALS tag is set to YES all external classes will be listed
# in the class index. If set to NO only the inherited external classes
# will be listed.
ALLEXTERNALS = NO
# The PERL_PATH should be the absolute path and name of the perl script
# interpreter (i.e. the result of `which perl').
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
# available from the path. This tool is part of Graphviz, a graph visualization
# toolkit from AT&T and Lucent Bell Labs. The other options in this section
# have no effect if this option is set to NO (the default)
HAVE_DOT = NO
# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
# will generate a graph for each documented class showing the direct and
# indirect inheritance relations. Setting this tag to YES will force the
# the CLASS_DIAGRAMS tag to NO.
CLASS_GRAPH = YES
# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
# will generate a graph for each documented class showing the direct and
# indirect implementation dependencies (inheritance, containment, and
# class references variables) of the class with other documented classes.
COLLABORATION_GRAPH = YES
# If the ENABLE_PREPROCESSING, INCLUDE_GRAPH, and HAVE_DOT tags are set to
# YES then doxygen will generate a graph for each documented file showing
# the direct and indirect include dependencies of the file with other
# documented files.
INCLUDE_GRAPH = YES
# If the ENABLE_PREPROCESSING, INCLUDED_BY_GRAPH, and HAVE_DOT tags are set to
# YES then doxygen will generate a graph for each documented header file showing
# the documented files that directly or indirectly include this file
INCLUDED_BY_GRAPH = YES
# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
# will graphical hierarchy of all classes instead of a textual one.
GRAPHICAL_HIERARCHY = YES
# The tag DOT_PATH can be used to specify the path where the dot tool can be
# found. If left blank, it is assumed the dot tool can be found on the path.
DOT_PATH =
# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
# (in pixels) of the graphs generated by dot. If a graph becomes larger than
# this value, doxygen will try to truncate the graph, so that it fits within
# the specified constraint. Beware that most browsers cannot cope with very
# large images.
MAX_DOT_GRAPH_WIDTH = 1024
# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
# (in pixels) of the graphs generated by dot. If a graph becomes larger than
# this value, doxygen will try to truncate the graph, so that it fits within
# the specified constraint. Beware that most browsers cannot cope with very
# large images.
MAX_DOT_GRAPH_HEIGHT = 1024
#---------------------------------------------------------------------------
# Configuration::addtions related to the search engine
#---------------------------------------------------------------------------
# The SEARCHENGINE tag specifies whether or not a search engine should be
# used. If set to NO the values of all tags below this one will be ignored.
SEARCHENGINE = NO
# The CGI_NAME tag should be the name of the CGI script that
# starts the search engine (doxysearch) with the correct parameters.
# A script with this name will be generated by doxygen.
CGI_NAME = search.cgi
# The CGI_URL tag should be the absolute URL to the directory where the
# cgi binaries are located. See the documentation of your http daemon for
# details.
CGI_URL =
# The DOC_URL tag should be the absolute URL to the directory where the
# documentation is located. If left blank the absolute path to the
# documentation, with file:// prepended to it, will be used.
DOC_URL =
# The DOC_ABSPATH tag should be the absolute path to the directory where the
# documentation is located. If left blank the directory on the local machine
# will be used.
DOC_ABSPATH =
# The BIN_ABSPATH tag must point to the directory where the doxysearch binary
# is installed.
BIN_ABSPATH = /usr/local/bin/
# The EXT_DOC_PATHS tag can be used to specify one or more paths to
# documentation generated for other projects. This allows doxysearch to search
# the documentation for these projects as well.
EXT_DOC_PATHS =

691
src/config/doxyscript.base Executable file
View File

@ -0,0 +1,691 @@
# Doxyfile 1.2.1
# This file describes the settings to be used by doxygen for a project
#
# All text after a hash (#) is considered a comment and will be ignored
# The format is:
# TAG = value [value, ...]
# For lists items can also be appended using:
# TAG += value [value, ...]
# Values that contain spaces should be placed between quotes (" ")
#---------------------------------------------------------------------------
# General configuration options
#---------------------------------------------------------------------------
# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
# by quotes) that should identify the project.
PROJECT_NAME = "LinuxBIOS"
# The PROJECT_NUMBER tag can be used to enter a project or revision number.
# This could be handy for archiving the generated documentation or
# if some version control system is used.
PROJECT_NUMBER =
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.
# If a relative path is entered, it will be relative to the location
# where doxygen was started. If left blank the current directory will be used.
OUTPUT_DIRECTORY = .
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
# documentation generated by doxygen is written. Doxygen will use this
# information to generate all constant output in the proper language.
# The default language is English, other supported languages are:
# Dutch, French, Italian, Czech, Swedish, German, Finnish, Japanese,
# Spanish, Russian, Croatian, Polish, and Portuguese.
OUTPUT_LANGUAGE = English
# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
# documentation are documented, even if no documentation was available.
# Private class members and static file members will be hidden unless
# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
EXTRACT_ALL = YES
# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
# will be included in the documentation.
EXTRACT_PRIVATE = YES
# If the EXTRACT_STATIC tag is set to YES all static members of a file
# will be included in the documentation.
EXTRACT_STATIC = YES
# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
# undocumented members of documented classes, files or namespaces.
# If set to NO (the default) these members will be included in the
# various overviews, but no documentation section is generated.
# This option has no effect if EXTRACT_ALL is enabled.
HIDE_UNDOC_MEMBERS = NO
# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
# undocumented classes that are normally visible in the class hierarchy.
# If set to NO (the default) these class will be included in the various
# overviews. This option has no effect if EXTRACT_ALL is enabled.
HIDE_UNDOC_CLASSES = NO
# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
# include brief member descriptions after the members that are listed in
# the file and class documentation (similar to JavaDoc).
# Set to NO to disable this.
BRIEF_MEMBER_DESC = YES
# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
# the brief description of a member or function before the detailed description.
# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
# brief descriptions will be completely suppressed.
REPEAT_BRIEF = YES
# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
# Doxygen will generate a detailed section even if there is only a brief
# description.
ALWAYS_DETAILED_SEC = NO
# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
# path before files name in the file list and in the header files. If set
# to NO the shortest path that makes the file name unique will be used.
FULL_PATH_NAMES = NO
# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
# can be used to strip a user defined part of the path. Stripping is
# only done if one of the specified strings matches the left-hand part of
# the path. It is allowed to use relative paths in the argument list.
STRIP_FROM_PATH =
# The INTERNAL_DOCS tag determines if documentation
# that is typed after a \internal command is included. If the tag is set
# to NO (the default) then the documentation will be excluded.
# Set it to YES to include the internal documentation.
INTERNAL_DOCS = NO
# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
# generate a class diagram (in Html and LaTeX) for classes with base or
# super classes. Setting the tag to NO turns the diagrams off.
CLASS_DIAGRAMS = YES
# If the SOURCE_BROWSER tag is set to YES then a list of source files will
# be generated. Documented entities will be cross-referenced with these sources.
SOURCE_BROWSER = YES
# Setting the INLINE_SOURCES tag to YES will include the body
# of functions and classes directly in the documentation.
INLINE_SOURCES = NO
# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
# doxygen to hide any special comment blocks from generated source code
# fragments. Normal C and C++ comments will always remain visible.
STRIP_CODE_COMMENTS = YES
# If the CASE_SENSE_NAMES tag is set to NO (the default) then Doxygen
# will only generate file names in lower case letters. If set to
# YES upper case letters are also allowed. This is useful if you have
# classes or files whose names only differ in case and if your file system
# supports case sensitive file names.
CASE_SENSE_NAMES = YES
# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
# will show members with their full class and namespace scopes in the
# documentation. If set to YES the scope will be hidden.
HIDE_SCOPE_NAMES = NO
# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
# will generate a verbatim copy of the header file for each class for
# which an include is specified. Set to NO to disable this.
VERBATIM_HEADERS = YES
# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
# will put list of the files that are included by a file in the documentation
# of that file.
SHOW_INCLUDE_FILES = YES
# If the JAVADOC_AUTOBRIEF tag is set to YES (the default) then Doxygen
# will interpret the first line (until the first dot) of a JavaDoc-style
# comment as the brief description. If set to NO, the Javadoc-style will
# behave just like the Qt-style comments.
JAVADOC_AUTOBRIEF = YES
# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
# member inherits the documentation from any documented member that it
# reimplements.
INHERIT_DOCS = YES
# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
# is inserted in the documentation for inline members.
INLINE_INFO = YES
# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
# will sort the (detailed) documentation of file and class members
# alphabetically by member name. If set to NO the members will appear in
# declaration order.
SORT_MEMBER_DOCS = YES
# The TAB_SIZE tag can be used to set the number of spaces in a tab.
# Doxygen uses this value to replace tabs by spaces in code fragments.
TAB_SIZE = 8
# The ENABLE_SECTIONS tag can be used to enable conditional
# documentation sections, marked by \if sectionname ... \endif.
ENABLED_SECTIONS =
# The GENERATE_TODOLIST tag can be used to enable (YES) or
# disable (NO) the todo list. This list is created by putting \todo
# commands in the documentation.
GENERATE_TODOLIST = YES
# The GENERATE_TESTLIST tag can be used to enable (YES) or
# disable (NO) the test list. This list is created by putting \test
# commands in the documentation.
GENERATE_TESTLIST = YES
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
# The QUIET tag can be used to turn on/off the messages that are generated
# by doxygen. Possible values are YES and NO. If left blank NO is used.
QUIET = NO
# The WARNINGS tag can be used to turn on/off the warning messages that are
# generated by doxygen. Possible values are YES and NO. If left blank
# NO is used.
WARNINGS = YES
# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
# automatically be disabled.
WARN_IF_UNDOCUMENTED = YES
# The WARN_FORMAT tag determines the format of the warning messages that
# doxygen can produce. The string should contain the $file, $line, and $text
# tags, which will be replaced by the file and line number from which the
# warning originated and the warning text.
WARN_FORMAT = "$file:$line: $text"
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
# The INPUT tag can be used to specify the files and/or directories that contain
# documented source files. You may enter file names like "myfile.cpp" or
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
# INPUT = ../src
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
# and *.h) to filter out the source-files in the directories. If left
# blank all files are included.
# FILE_PATTERNS = *.c *.h *.S
# The RECURSIVE tag can be used to turn specify whether or not subdirectories
# should be searched for input files as well. Possible values are YES and NO.
# If left blank NO is used.
RECURSIVE = YES
# The EXCLUDE tag can be used to specify files and/or directories that should
# excluded from the INPUT source files. This way you can easily exclude a
# subdirectory from a directory tree whose root is specified with the INPUT tag.
EXCLUDE =
# If the value of the INPUT tag contains directories, you can use the
# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
# certain files from those directories.
EXCLUDE_PATTERNS =
# The EXAMPLE_PATH tag can be used to specify one or more files or
# directories that contain example code fragments that are included (see
# the \include command).
EXAMPLE_PATH =
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
# and *.h) to filter out the source-files in the directories. If left
# blank all files are included.
EXAMPLE_PATTERNS =
# The IMAGE_PATH tag can be used to specify one or more files or
# directories that contain image that are included in the documentation (see
# the \image command).
IMAGE_PATH =
# The INPUT_FILTER tag can be used to specify a program that doxygen should
# invoke to filter for each input file. Doxygen will invoke the filter program
# by executing (via popen()) the command <filter> <input-file>, where <filter>
# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
# input file. Doxygen will then use the output that the filter program writes
# to standard output.
INPUT_FILTER =
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
# of all compounds will be generated. Enable this if the project
# contains a lot of classes, structs, unions or interfaces.
ALPHABETICAL_INDEX = NO
# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
# in which this list will be split (can be a number in the range [1..20])
COLS_IN_ALPHA_INDEX = 5
# In case all classes in a project start with a common prefix, all
# classes will be put under the same header in the alphabetical index.
# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
# should be ignored while generating the index headers.
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# configuration options related to the HTML output
#---------------------------------------------------------------------------
# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
# generate HTML output.
GENERATE_HTML = YES
# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `html' will be used as the default path.
HTML_OUTPUT = html
# The HTML_HEADER tag can be used to specify a personal HTML header for
# each generated HTML page. If it is left blank doxygen will generate a
# standard header.
HTML_HEADER =
# The HTML_FOOTER tag can be used to specify a personal HTML footer for
# each generated HTML page. If it is left blank doxygen will generate a
# standard footer.
HTML_FOOTER =
# The HTML_STYLESHEET tag can be used to specify a user defined cascading
# style sheet that is used by each HTML page. It can be used to
# fine-tune the look of the HTML output. If the tag is left blank doxygen
# will generate a default style sheet
HTML_STYLESHEET =
# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
# files or namespaces will be aligned in HTML using tables. If set to
# NO a bullet list will be used.
HTML_ALIGN_MEMBERS = YES
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
# will be generated that can be used as input for tools like the
# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
# of the generated HTML documentation.
GENERATE_HTMLHELP = NO
# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
# top of each HTML page. The value NO (the default) enables the index and
# the value YES disables it.
DISABLE_INDEX = NO
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
# generate Latex output.
GENERATE_LATEX = YES
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `latex' will be used as the default path.
LATEX_OUTPUT = latex
# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
# LaTeX documents. This may be useful for small projects and may help to
# save some trees in general.
COMPACT_LATEX = NO
# The PAPER_TYPE tag can be used to set the paper type that is used
# by the printer. Possible values are: a4, a4wide, letter, legal and
# executive. If left blank a4wide will be used.
PAPER_TYPE = a4wide
# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
# packages that should be included in the LaTeX output.
EXTRA_PACKAGES =
# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
# the generated latex document. The header should contain everything until
# the first chapter. If it is left blank doxygen will generate a
# standard header. Notice: only use this tag if you know what you are doing!
LATEX_HEADER =
# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
# is prepared for conversion to pdf (using ps2pdf). The pdf file will
# contain links (just like the HTML output) instead of page references
# This makes the output suitable for online browsing using a pdf viewer.
PDF_HYPERLINKS = NO
# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
# plain latex in the generated Makefile. Set this option to YES to get a
# higher quality PDF documentation.
USE_PDFLATEX = NO
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
# command to the generated LaTeX files. This will instruct LaTeX to keep
# running if errors occur, instead of asking the user for help.
# This option is also used when generating formulas in HTML.
LATEX_BATCHMODE = NO
#---------------------------------------------------------------------------
# configuration options related to the RTF output
#---------------------------------------------------------------------------
# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
# The RTF output is optimised for Word 97 and may not look very pretty with
# other RTF readers or editors.
GENERATE_RTF = YES
# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `rtf' will be used as the default path.
RTF_OUTPUT = rtf
# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
# RTF documents. This may be useful for small projects and may help to
# save some trees in general.
COMPACT_RTF = NO
# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
# will contain hyperlink fields. The RTF file will
# contain links (just like the HTML output) instead of page references.
# This makes the output suitable for online browsing using a WORD or other.
# programs which support those fields.
# Note: wordpad (write) and others do not support links.
RTF_HYPERLINKS = NO
# Load stylesheet definitions from file. Syntax is similar to doxygen's
# config file, i.e. a series of assigments. You only have to provide
# replacements, missing definitions are set to their default value.
RTF_STYLESHEET_FILE =
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
# generate man pages
GENERATE_MAN = YES
# The MAN_OUTPUT tag is used to specify where the man pages will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `man' will be used as the default path.
MAN_OUTPUT = man
# The MAN_EXTENSION tag determines the extension that is added to
# the generated man pages (default is the subroutine's section .3)
MAN_EXTENSION = .3
#---------------------------------------------------------------------------
# configuration options related to the XML output
#---------------------------------------------------------------------------
# If the GENERATE_XML tag is set to YES Doxygen will
# generate an XML file that captures the structure of
# the code including all documentation. Warning: This feature
# is still experimental and very incomplete.
GENERATE_XML = NO
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
# evaluate all C-preprocessor directives found in the sources and include
# files.
ENABLE_PREPROCESSING = YES
# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
# names in the source code. If set to NO (the default) only conditional
# compilation will be performed. Macro expansion can be done in a controlled
# way by setting EXPAND_ONLY_PREDEF to YES.
MACRO_EXPANSION = NO
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
# then the macro expansion is limited to the macros specified with the
# PREDEFINED and EXPAND_AS_PREDEFINED tags.
EXPAND_ONLY_PREDEF = NO
# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
# in the INCLUDE_PATH (see below) will be search if a #include is found.
SEARCH_INCLUDES = YES
# The INCLUDE_PATH tag can be used to specify one or more directories that
# contain include files that are not input files but should be processed by
# the preprocessor.
INCLUDE_PATH =
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
# patterns (like *.h and *.hpp) to filter out the header-files in the
# directories. If left blank, the patterns specified with FILE_PATTERNS will
# be used.
INCLUDE_FILE_PATTERNS =
# The PREDEFINED tag can be used to specify one or more macro names that
# are defined before the preprocessor is started (similar to the -D option of
# gcc). The argument of the tag is a list of macros of the form: name
# or name=definition (no spaces). If the definition and the = are
# omitted =1 is assumed.
PREDEFINED =
# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then
# this tag can be used to specify a list of macro names that should be expanded.
# The macro definition that is found in the sources will be used.
# Use the PREDEFINED tag if you want to use a different macro definition.
EXPAND_AS_DEFINED =
#---------------------------------------------------------------------------
# Configuration::addtions related to external references
#---------------------------------------------------------------------------
# The TAGFILES tag can be used to specify one or more tagfiles.
TAGFILES =
# When a file name is specified after GENERATE_TAGFILE, doxygen will create
# a tag file that is based on the input files it reads.
GENERATE_TAGFILE =
# If the ALLEXTERNALS tag is set to YES all external classes will be listed
# in the class index. If set to NO only the inherited external classes
# will be listed.
ALLEXTERNALS = NO
# The PERL_PATH should be the absolute path and name of the perl script
# interpreter (i.e. the result of `which perl').
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
# available from the path. This tool is part of Graphviz, a graph visualization
# toolkit from AT&T and Lucent Bell Labs. The other options in this section
# have no effect if this option is set to NO (the default)
HAVE_DOT = NO
# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
# will generate a graph for each documented class showing the direct and
# indirect inheritance relations. Setting this tag to YES will force the
# the CLASS_DIAGRAMS tag to NO.
CLASS_GRAPH = YES
# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
# will generate a graph for each documented class showing the direct and
# indirect implementation dependencies (inheritance, containment, and
# class references variables) of the class with other documented classes.
COLLABORATION_GRAPH = YES
# If the ENABLE_PREPROCESSING, INCLUDE_GRAPH, and HAVE_DOT tags are set to
# YES then doxygen will generate a graph for each documented file showing
# the direct and indirect include dependencies of the file with other
# documented files.
INCLUDE_GRAPH = YES
# If the ENABLE_PREPROCESSING, INCLUDED_BY_GRAPH, and HAVE_DOT tags are set to
# YES then doxygen will generate a graph for each documented header file showing
# the documented files that directly or indirectly include this file
INCLUDED_BY_GRAPH = YES
# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
# will graphical hierarchy of all classes instead of a textual one.
GRAPHICAL_HIERARCHY = YES
# The tag DOT_PATH can be used to specify the path where the dot tool can be
# found. If left blank, it is assumed the dot tool can be found on the path.
DOT_PATH =
# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
# (in pixels) of the graphs generated by dot. If a graph becomes larger than
# this value, doxygen will try to truncate the graph, so that it fits within
# the specified constraint. Beware that most browsers cannot cope with very
# large images.
MAX_DOT_GRAPH_WIDTH = 1024
# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
# (in pixels) of the graphs generated by dot. If a graph becomes larger than
# this value, doxygen will try to truncate the graph, so that it fits within
# the specified constraint. Beware that most browsers cannot cope with very
# large images.
MAX_DOT_GRAPH_HEIGHT = 1024
#---------------------------------------------------------------------------
# Configuration::addtions related to the search engine
#---------------------------------------------------------------------------
# The SEARCHENGINE tag specifies whether or not a search engine should be
# used. If set to NO the values of all tags below this one will be ignored.
SEARCHENGINE = NO
# The CGI_NAME tag should be the name of the CGI script that
# starts the search engine (doxysearch) with the correct parameters.
# A script with this name will be generated by doxygen.
CGI_NAME = search.cgi
# The CGI_URL tag should be the absolute URL to the directory where the
# cgi binaries are located. See the documentation of your http daemon for
# details.
CGI_URL =
# The DOC_URL tag should be the absolute URL to the directory where the
# documentation is located. If left blank the absolute path to the
# documentation, with file:// prepended to it, will be used.
DOC_URL =
# The DOC_ABSPATH tag should be the absolute path to the directory where the
# documentation is located. If left blank the directory on the local machine
# will be used.
DOC_ABSPATH =
# The BIN_ABSPATH tag must point to the directory where the doxysearch binary
# is installed.
BIN_ABSPATH = /usr/local/bin/
# The EXT_DOC_PATHS tag can be used to specify one or more paths to
# documentation generated for other projects. This allows doxysearch to search
# the documentation for these projects as well.
EXT_DOC_PATHS =

112
src/config/linuxbios_c.ld Normal file
View File

@ -0,0 +1,112 @@
/*
* Memory map:
*
* _RAMBASE
* : data segment
* : bss segment
* : heap
* : stack
*/
/*
* Bootstrap code for the STPC Consumer
* Copyright (c) 1999 by Net Insight AB. All Rights Reserved.
*
* $Id$
*
*/
/*
* Written by Johan Rydberg, based on work by Daniel Kahlin.
* Rewritten by Eric Biederman
*/
/*
* We use ELF as output format. So that we can
* debug the code in some form.
*/
INCLUDE ldoptions
ENTRY(_start)
SECTIONS
{
. = _RAMBASE;
/*
* First we place the code and read only data (typically const declared).
* This get placed in rom.
*/
.text : {
_text = .;
*(.text);
*(.text.*);
. = ALIGN(16);
_etext = .;
}
.rodata : {
_rodata = .;
. = ALIGN(4);
console_drivers = .;
*(.rodata.console_drivers)
econsole_drivers = . ;
. = ALIGN(4);
pci_drivers = . ;
*(.rodata.pci_drivers)
epci_drivers = . ;
*(.rodata)
*(.rodata.*)
/*
* kevinh/Ispiri - Added an align, because the objcopy tool
* incorrectly converts sections that are not long word aligned.
* This breaksthe linuxbios.strip target.
*/
. = ALIGN(4);
_erodata = .;
}
/*
* After the code we place initialized data (typically initialized
* global variables). This gets copied into ram by startup code.
* __data_start and __data_end shows where in ram this should be placed,
* whereas __data_loadstart and __data_loadend shows where in rom to
* copy from.
*/
.data : {
_data = .;
*(.data)
_edata = .;
}
/*
* bss does not contain data, it is just a space that should be zero
* initialized on startup. (typically uninitialized global variables)
* crt0.S fills between _bss and _ebss with zeroes.
*/
_bss = .;
.bss . : {
*(.bss)
*(.sbss)
*(COMMON)
}
_ebss = .;
_end = .;
_stack = .;
.stack . : {
/* Reserve a stack for each possible cpu, +1 extra */
. = ((MAX_CPUS * STACK_SIZE) + STACK_SIZE) ;
}
_estack = .;
_heap = .;
.heap . : {
/* Reserve 256K for the heap */
. = HEAP_SIZE ;
. = ALIGN(4);
}
_eheap = .;
/* The ram segment
* This is all address of the memory resident copy of linuxBIOS.
*/
_ram_seg = _text;
_eram_seg = _eheap;
/DISCARD/ : {
*(.comment)
*(.note)
}
}

75
src/console/console.c Normal file
View File

@ -0,0 +1,75 @@
/*
* Bootstrap code for the INTEL
* $Id$
*
*/
#include <arch/io.h>
#include <console/console.h>
#include <string.h>
#include <pc80/mc146818rtc.h>
static int initialized;
/* initialize the console */
void console_init(void)
{
struct console_driver *driver;
if(get_option(&console_loglevel, "debug_level"))
console_loglevel=DEFAULT_CONSOLE_LOGLEVEL;
for(driver = console_drivers; driver < econsole_drivers; driver++) {
if (!driver->init)
continue;
driver->init();
}
initialized = 1;
}
static void __console_tx_byte(unsigned char byte)
{
struct console_driver *driver;
for(driver = console_drivers; driver < econsole_drivers; driver++) {
driver->tx_byte(byte);
}
}
void console_tx_flush(void)
{
struct console_driver *driver;
for(driver = console_drivers; driver < econsole_drivers; driver++) {
if (!driver->tx_flush)
continue;
driver->tx_flush();
}
}
void console_tx_byte(unsigned char byte)
{
if (!initialized)
return;
if (byte == '\n')
__console_tx_byte('\r');
__console_tx_byte(byte);
}
/*
* Write POST information
*/
void post_code(uint8_t value)
{
#ifdef CONFIG_SERIAL_POST
printk_info("POST: 0x%02x\n", value);
#elsif !define(NO_POST)
outb(value, 0x80);
#endif
}
/* Report a fatal error */
void die(char *msg)
{
printk_emerg("%s", msg);
post_code(0xff);
while (1); /* Halt */
}

View File

@ -0,0 +1,19 @@
#include <console/console.h>
#define LOGBUF_SIZE 1024
// KEEP THIS GLOBAL.
// I need the address so I can watch it with the ARIUM hardware. RGM.
char logbuf[LOGBUF_SIZE];
int logbuf_offset = 0;
static void logbuf_tx_byte(unsigned char byte)
{
logbuf[logbuf_offset] = byte;
logbuf_offset = (logbuf_offset +1) % LOGBUF_SIZE;
}
static struct console_driver __console = {
.init = 0,
.tx_byte = logbuf_tx_byte,
};}

56
src/console/printk.c Normal file
View File

@ -0,0 +1,56 @@
/*
* blantantly copied from linux/kernel/printk.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
*/
#ifndef lint
static char rcsid[] = "$Id$";
#endif
//typedef void * va_list;
#include <stdarg.h>
#include <smp/spinlock.h>
#include <console/console.h>
/* printk's without a loglevel use this.. */
#define DEFAULT_MESSAGE_LOGLEVEL 4 /* BIOS_WARNING */
/* We show everything that is MORE important than this.. */
#define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */
/* Keep together for sysctl support */
int console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
int default_message_loglevel = DEFAULT_MESSAGE_LOGLEVEL;
int minimum_console_loglevel = MINIMUM_CONSOLE_LOGLEVEL;
int default_console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
void display(char*);
extern int vtxprintf(void (*)(unsigned char), const char *, va_list);
spinlock_t console_lock = SPIN_LOCK_UNLOCKED;
int do_printk(int msg_level, const char *fmt, ...)
{
va_list args;
int i;
if (msg_level >= console_loglevel) {
return 0;
}
spin_lock(&console_lock);
va_start(args, fmt);
i = vtxprintf(console_tx_byte, fmt, args);
va_end(args);
console_tx_flush();
spin_unlock(&console_lock);
return i;
}

View File

@ -0,0 +1,49 @@
#include <console/console.h>
#include <uart8250.h>
#include <pc80/mc146818rtc.h>
/* Base Address */
#ifndef TTYS0_BASE
#define TTYS0_BASE 0x3f8
#endif
#ifndef TTYS0_BAUD
#define TTYS0_BAUD 115200
#endif
#if ((115200%TTYS0_BAUD) != 0)
#error Bad ttys0 baud rate
#endif
#define TTYS0_DIV (115200/TTYS0_BAUD)
/* Line Control Settings */
#ifndef TTYS0_LCS
/* Set 8bit, 1 stop bit, no parity */
#define TTYS0_LCS 0x3
#endif
#define UART_LCS TTYS0_LCS
void ttyS0_init(void)
{
static unsigned char div[8]={1,2,3,6,12,24,48,96};
int b_index=0;
unsigned int divisor=TTYS0_DIV;
if(get_option(&b_index,"baud_rate")==0) {
divisor=div[b_index];
}
uart8250_init(TTYS0_BASE, divisor, TTYS0_LCS);
}
void ttyS0_tx_byte(unsigned char data)
{
uart8250_tx_byte(TTYS0_BASE, data);
}
static struct console_driver uart8250_console __console = {
.init = ttyS0_init,
.tx_byte = ttyS0_tx_byte,
};

100
src/console/vga_console.c Normal file
View File

@ -0,0 +1,100 @@
/*
*
* modified from original freebios code
* by Steve M. Gehlbach <steve@kesa.com>
*
*/
#include <arch/io.h>
#include <string.h>
#include <pc80/vga.h>
#include <console/console.h>
void beep(int ms);
static char *vidmem; /* The video buffer, should be replaced by symbol in ldscript.ld */
int vga_line, vga_col;
#define VIDBUFFER 0xB8000;
static void memsetw(void *s, int c, unsigned int n)
{
int i;
u16 *ss = (u16 *) s;
for (i = 0; i < n; i++) {
ss[i] = ( u16 ) c;
}
}
static void vga_init(void)
{
// these are globals
vga_line = 0;
vga_col = 0;
vidmem = (unsigned char *) VIDBUFFER;
// mainboard or chip specific init routines
// also loads font
vga_hardware_fixup();
// set attributes, char for entire screen
// font should be previously loaded in
// device specific code (vga_hardware_fixup)
memsetw(vidmem, VGA_ATTR_CLR_WHT, 2*1024); //
}
static void vga_scroll(void)
{
int i;
memcpy(vidmem, vidmem + COLS * 2, (LINES - 1) * COLS * 2);
for (i = (LINES - 1) * COLS * 2; i < LINES * COLS * 2; i += 2)
vidmem[i] = ' ';
}
static void vga_tx_byte(unsigned char byte)
{
if (byte == '\n') {
vga_line++;
vga_col = 0;
} else if (byte == '\r') {
vga_col = 0;
} else if (byte == '\b') {
vga_col--;
} else if (byte == '\t') {
vga_col += 4;
} else if (byte == '\a') {
//beep
beep(500);
} else {
vidmem[((vga_col + (vga_line *COLS)) * 2)] = byte;
vidmem[((vga_col + (vga_line *COLS)) * 2) +1] = VGA_ATTR_CLR_WHT;
vga_col++;
}
if (vga_col < 0) {
vga_col = 0;
}
if (vga_col >= COLS) {
vga_line++;
vga_col = 0;
}
if (vga_line >= LINES) {
vga_scroll();
vga_line--;
}
// move the cursor
write_crtc((vga_col + (vga_line *COLS)) >> 8, CRTC_CURSOR_HI);
write_crtc((vga_col + (vga_line *COLS)) & 0x0ff, CRTC_CURSOR_LO);
}
struct console_driver {
.init = vga_init,
.tx_byte = vga_tx_byte,
};

352
src/console/vsprintf.c Normal file
View File

@ -0,0 +1,352 @@
/*
* linux/lib/vsprintf.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
/*
* Wirzenius wrote this portably, Torvalds fucked it up :-)
*/
#ifndef lint
static char rcsid[] = "$Id$";
#endif
#include <stdarg.h>
#include <string.h>
/* haha, don't need ctype.c */
#define isdigit(c) ((c) >= '0' && (c) <= '9')
#define is_digit isdigit
#define isxdigit(c) (((c) >= '0' && (c) <= '9') || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F'))
#define islower(c) ((c) >= 'a' && (c) <= 'z')
#define toupper(c) __toupper(c)
static inline unsigned char __toupper(unsigned char c)
{
if (islower(c))
c -= 'a'-'A';
return c;
}
unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
{
unsigned long result = 0,value;
if (!base) {
base = 10;
if (*cp == '0') {
base = 8;
cp++;
if ((*cp == 'x') && isxdigit(cp[1])) {
cp++;
base = 16;
}
}
}
while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
? toupper(*cp) : *cp)-'A'+10) < base) {
result = result*base + value;
cp++;
}
if (endp)
*endp = (char *)cp;
return result;
}
long simple_strtol(const char *cp,char **endp,unsigned int base)
{
if(*cp=='-')
return -simple_strtoul(cp+1,endp,base);
return simple_strtoul(cp,endp,base);
}
static int skip_atoi(const char **s)
{
int i=0;
while (is_digit(**s))
i = i*10 + *((*s)++) - '0';
return i;
}
#define ZEROPAD 1 /* pad with zero */
#define SIGN 2 /* unsigned/signed long */
#define PLUS 4 /* show plus */
#define SPACE 8 /* space if plus */
#define LEFT 16 /* left justified */
#define SPECIAL 32 /* 0x */
#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
#define do_div(n,base) ({ \
int __res; \
__res = ((unsigned long) n) % (unsigned) base; \
n = ((unsigned long) n) / (unsigned) base; \
__res; })
static int number(void (*tx_byte)(unsigned char byte), long num, int base, int size, int precision
,int type)
{
char c,sign,tmp[66];
const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
int i;
int count = 0;
if (type & LARGE)
digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (type & LEFT)
type &= ~ZEROPAD;
if (base < 2 || base > 36)
return 0;
c = (type & ZEROPAD) ? '0' : ' ';
sign = 0;
if (type & SIGN) {
if (num < 0) {
sign = '-';
num = -num;
size--;
} else if (type & PLUS) {
sign = '+';
size--;
} else if (type & SPACE) {
sign = ' ';
size--;
}
}
if (type & SPECIAL) {
if (base == 16)
size -= 2;
else if (base == 8)
size--;
}
i = 0;
if (num == 0)
tmp[i++]='0';
else while (num != 0)
tmp[i++] = digits[do_div(num,base)];
if (i > precision)
precision = i;
size -= precision;
if (!(type&(ZEROPAD+LEFT)))
while(size-->0)
tx_byte(' '), count++;
if (sign)
tx_byte(sign), count++;
if (type & SPECIAL) {
if (base==8)
tx_byte('0'), count++;
else if (base==16) {
tx_byte('0'), count++;
tx_byte(digits[33]), count++;
}
}
if (!(type & LEFT))
while (size-- > 0)
tx_byte(c), count++;
while (i < precision--)
tx_byte('0'), count++;
while (i-- > 0)
tx_byte(tmp[i]), count++;
while (size-- > 0)
tx_byte(' '), count++;
return count;
}
int vtxprintf(void (*tx_byte)(unsigned char byte), const char *fmt, va_list args)
{
int len;
unsigned long num;
int i, base;
const char *s;
int flags; /* flags to number() */
int field_width; /* width of output field */
int precision; /* min. # of digits for integers; max
number of chars for from string */
int qualifier; /* 'h', 'l', or 'L' for integer fields */
int count;
for (count=0; *fmt ; ++fmt) {
if (*fmt != '%') {
tx_byte(*fmt), count++;
continue;
}
/* process flags */
flags = 0;
repeat:
++fmt; /* this also skips first '%' */
switch (*fmt) {
case '-': flags |= LEFT; goto repeat;
case '+': flags |= PLUS; goto repeat;
case ' ': flags |= SPACE; goto repeat;
case '#': flags |= SPECIAL; goto repeat;
case '0': flags |= ZEROPAD; goto repeat;
}
/* get field width */
field_width = -1;
if (is_digit(*fmt))
field_width = skip_atoi(&fmt);
else if (*fmt == '*') {
++fmt;
/* it's the next argument */
field_width = va_arg(args, int);
if (field_width < 0) {
field_width = -field_width;
flags |= LEFT;
}
}
/* get the precision */
precision = -1;
if (*fmt == '.') {
++fmt;
if (is_digit(*fmt))
precision = skip_atoi(&fmt);
else if (*fmt == '*') {
++fmt;
/* it's the next argument */
precision = va_arg(args, int);
}
if (precision < 0)
precision = 0;
}
/* get the conversion qualifier */
qualifier = -1;
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
qualifier = *fmt;
++fmt;
}
/* default base */
base = 10;
switch (*fmt) {
case 'c':
if (!(flags & LEFT))
while (--field_width > 0)
tx_byte(' '), count++;
tx_byte((unsigned char) va_arg(args, int)), count++;
while (--field_width > 0)
tx_byte(' '), count++;
continue;
case 's':
s = va_arg(args, char *);
if (!s)
s = "<NULL>";
len = strnlen(s, precision);
if (!(flags & LEFT))
while (len < field_width--)
tx_byte(' '), count++;
for (i = 0; i < len; ++i)
tx_byte(*s++), count++;
while (len < field_width--)
tx_byte(' '), count++;
continue;
case 'p':
if (field_width == -1) {
field_width = 2*sizeof(void *);
flags |= ZEROPAD;
}
count += number(tx_byte,
(unsigned long) va_arg(args, void *), 16,
field_width, precision, flags);
continue;
case 'n':
if (qualifier == 'l') {
long * ip = va_arg(args, long *);
*ip = count;
} else {
int * ip = va_arg(args, int *);
*ip = count;
}
continue;
case '%':
tx_byte('%'), count++;
continue;
/* integer number formats - set up the flags and "break" */
case 'o':
base = 8;
break;
case 'X':
flags |= LARGE;
case 'x':
base = 16;
break;
case 'd':
case 'i':
flags |= SIGN;
case 'u':
break;
default:
tx_byte('%'), count++;
if (*fmt)
tx_byte(*fmt), count++;
else
--fmt;
continue;
}
if (qualifier == 'l')
num = va_arg(args, unsigned long);
else if (qualifier == 'h') {
num = (unsigned short) va_arg(args, int);
if (flags & SIGN)
num = (short) num;
} else if (flags & SIGN)
num = va_arg(args, int);
else
num = va_arg(args, unsigned int);
count += number(tx_byte, num, base, field_width, precision, flags);
}
return count;
}
/* FIXME this global makes vsprintf non-reentrant
*/
static char *str_buf;
static void str_tx_byte(unsigned char byte)
{
*str_buf = byte;
str_buf++;
}
int vsprintf(char * buf, const char *fmt, va_list args)
{
int i;
str_buf = buf;
i = vtxprintf(str_tx_byte, fmt, args);
/* maeder/Ispiri -- The null termination was missing a deference */
/* and was just zeroing out the pointer instead */
*str_buf = '\0';
return i;
}
int sprintf(char * buf, const char *fmt, ...)
{
va_list args;
int i;
va_start(args, fmt);
i=vsprintf(buf,fmt,args);
va_end(args);
return i;
}

112
src/cpu/i386/entry16.inc Normal file
View File

@ -0,0 +1,112 @@
/*
This software and ancillary information (herein called SOFTWARE )
called LinuxBIOS is made available under the terms described
here. The SOFTWARE has been approved for release with associated
LA-CC Number 00-34 . Unless otherwise indicated, this SOFTWARE has
been authored by an employee or employees of the University of
California, operator of the Los Alamos National Laboratory under
Contract No. W-7405-ENG-36 with the U.S. Department of Energy. The
U.S. Government has rights to use, reproduce, and distribute this
SOFTWARE. The public may copy, distribute, prepare derivative works
and publicly display this SOFTWARE without charge, provided that this
Notice and any statement of authorship are reproduced on all copies.
Neither the Government nor the University makes any warranty, express
or implied, or assumes any liability or responsibility for the use of
this SOFTWARE. If SOFTWARE is modified to produce derivative works,
such modified SOFTWARE should be clearly marked, so as not to confuse
it with the version available from LANL.
*/
/* Copyright 2000, Ron Minnich, Advanced Computing Lab, LANL
* rminnich@lanl.gov
*/
/** Start code to put an i386 or later processor into 32-bit
* protected mode.
*/
/* .section ".rom.text" */
#include <arch/rom_segs.h>
.code16
.globl EXT(_start)
.type EXT(_start), @function
EXT(_start):
cli
/* thanks to kmliu@sis.tw.com for this TBL fix ... */
/**/
/* IMMEDIATELY invalidate the translation lookaside buffer before executing*/
/* any further code. Even though paging is disabled we could still get*/
/*false address translations due to the TLB if we didn't invalidate it.*/
/**/
xorl %eax, %eax
movl %eax, %cr3 /* Invalidate TLB*/
/* invalidate the cache */
invd
/* Note: gas handles memory addresses in 16 bit code very poorly.
* In particular it doesn't appear to have a directive allowing you
* associate a section or even an absolute offset with a segment register.
*
* This means that anything except cs:ip relative offsets are
* a real pain in 16 bit mode. And explains why it is almost
* imposible to get gas to do lgdt correctly.
*
* One way to work around this is to have the linker do the
* math instead of the assembler. This solves the very
* pratical problem of being able to write code that can
* be relocated.
*
* An lgdt call before we have memory enabled cannot be
* position independent, as we cannot execute a call
* instruction to get our current instruction pointer.
* So while this code is relocateable it isn't arbitrarily
* relocatable.
*
* The criteria for relocation have been relaxed to their
* utmost, so that we can use the same code for both
* our initial entry point and startup of the second cpu.
* The code assumes when executing at _start that:
* (((cs & 0xfff) == 0) and (ip == _start & 0xffff))
* or
* ((cs == anything) and (ip == 0)).
*
* The restrictions in reset16.inc mean that _start initially
* must be loaded at or above 0xffff0000 or below 0x100000.
*
* The linker scripts computs gdtptr16_offset by simply returning
* the low 16 bits. This means that the intial segment used
* when start is called must be 64K aligned. This should not
* restrict the address as the ip address can be anything.
*/
movw %cs, %ax
shlw $4, %ax
movw $EXT(gdtptr16_offset), %bx
subw %ax, %bx
data32 lgdt %cs:(%bx)
movl %cr0, %eax
andl $0x7FFAFFD1, %eax /* PG,AM,WP,NE,TS,EM,MP = 0 */
orl $0x60000001, %eax /* CD, NW, PE = 1 */
movl %eax, %cr0
/* Now that we are in protected mode jump to a 32 bit code segment. */
data32 ljmp $ROM_CODE_SEG, $__protected_start
/** The gdt has a 4 Gb code segment at 0x10, and a 4 GB data segment
* at 0x18; these are Linux-compatible.
*/
.align 4
.globl EXT(gdtptr16)
EXT(gdtptr16):
.word gdt_end - gdt -1 /* compute the table limit */
.long gdt /* we know the offset */
.globl EXT(_estart)
EXT(_estart):
.code32

2
src/cpu/i386/entry16.lds Normal file
View File

@ -0,0 +1,2 @@
gdtptr16_offset = gdtptr16 & 0xffff;
_start_offset = _start & 0xffff;

55
src/cpu/i386/entry32.inc Normal file
View File

@ -0,0 +1,55 @@
/* For starting linuxBIOS in protected mode */
#include <arch/rom_segs.h>
/* .section ".rom.text" */
.code32
.align 4
.globl EXT(gdtptr)
gdt:
EXT(gdtptr):
.word gdt_end - gdt -1 /* compute the table limit */
.long gdt /* we know the offset */
.word 0
/* flat code segment */
.word 0xffff, 0x0000
.byte 0x00, 0x9b, 0xcf, 0x00
/* flat data segment */
.word 0xffff, 0x0000
.byte 0x00, 0x93, 0xcf, 0x00
gdt_end:
/*
* When we come here we are in protected mode. We expand
* the stack and copies the data segment from ROM to the
* memory.
*
* After that, we call the chipset bootstrap routine that
* does what is left of the chipset initialization.
*
* NOTE aligned to 4 so that we are sure that the prefetch
* cache will be reloaded.
*/
.align 4
.globl EXT(protected_start)
EXT(protected_start):
lgdt %cs:gdtptr
ljmp $ROM_CODE_SEG, $__protected_start
__protected_start:
intel_chip_post_macro(0x10) /* post 10 */
movw $ROM_DATA_SEG, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %ss
movw %ax, %fs
movw %ax, %gs

14
src/cpu/i386/entry32.lds Normal file
View File

@ -0,0 +1,14 @@
/*
_cache_ram_seg_base = DEFINED(CACHE_RAM_BASE)? CACHE_RAM_BASE - _rodata : 0;
_cache_ram_seg_base_low = (_cache_ram_seg_base) & 0xffff;
_cache_ram_seg_base_middle = (_cache_ram_seg_base >> 16) & 0xff;
_cache_ram_seg_base_high = (_cache_ram_seg_base >> 24) & 0xff;
_rom_code_seg_base = _ltext - _text;
_rom_code_seg_base_low = (_rom_code_seg_base) & 0xffff;
_rom_code_seg_base_middle = (_rom_code_seg_base >> 16) & 0xff;
_rom_code_seg_base_high = (_rom_code_seg_base >> 24) & 0xff;
*/

27
src/cpu/i386/reset16.inc Normal file
View File

@ -0,0 +1,27 @@
.section ".reset"
.code16
.globl EXT(reset_vector)
EXT(reset_vector):
#if _ROMBASE >= 0xffff0000
/* Hmm.
* _start_offset is the low 16 bits of _start.
* Theoretically we should have problems but it compiles
* and links properly with binutils 2.9.5 & 2.10.90
* This is probably a case that needs fixing in binutils.
* And then we can just use _start.
* We also need something like the assume directive in
* other assemblers to tell it where the segment registers
* are pointing in memory right now.
*/
jmp EXT(_start_offset)
#elif (_ROMBASE < 0x100000)
ljmp $((_ROMBASE & 0xf0000)>>4),$EXT(_start_offset);
#else
#error _ROMBASE is an unsupported value
#endif
. = 0x8;
.code32
jmp EXT(protected_start)
.previous

14
src/cpu/i386/reset16.lds Normal file
View File

@ -0,0 +1,14 @@
/*
* _ROMTOP : The top of the rom used where we
* need to put the reset vector.
*/
SECTIONS {
_ROMTOP = (_ROMBASE >= 0xffff0000)? 0xfffffff0 : 0xffff0;
. = _ROMTOP;
.reset . : {
*(.reset)
. = 15 ;
BYTE(0x00);
}
}

10
src/cpu/i386/reset32.inc Normal file
View File

@ -0,0 +1,10 @@
.section ".reset"
.code16
.globl EXT(reset_vector)
EXT(reset_vector):
. = 0x8;
.code32
jmp EXT(protected_start)
.previous

14
src/cpu/i386/reset32.lds Normal file
View File

@ -0,0 +1,14 @@
/*
* _ROMTOP : The top of the rom used where we
* need to put the reset vector.
*/
SECTIONS {
_ROMTOP = _ROMBASE + ROM_IMAGE_SIZE - 0x10;
. = _ROMTOP;
.reset (.): {
*(.reset)
. = 15 ;
BYTE(0x00);
}
}

59
src/cpu/k8/cpufixup.c Normal file
View File

@ -0,0 +1,59 @@
/* Needed so the AMD K8 runs correctly. */
#include <console/console.h>
#include <mem.h>
#include <cpu/p6/msr.h>
#define TOP_MEM 0xc001001A
#define TOP_MEM2 0xc001001D
#define IORR_FIRST 0xC0010016
#define IORR_LAST 0xC0010019
#define SYSCFG 0xC0010010
#define MTRRVARDRAMEN (1 << 20)
void k8_cpufixup(struct mem_range *mem)
{
unsigned long lo = 0, hi = 0, i;
unsigned long ram_megabytes;
/* For now no Athlon board has significant holes in it's
* address space so just find the last memory region
* and compute the end of memory from that.
*/
for(i = 0; mem[i].sizek; i++)
;
if (i == 0)
return;
ram_megabytes = (mem[i-1].basek + mem[i-1].sizek) *1024;
// 8 MB alignment please
ram_megabytes += 0x7fffff;
ram_megabytes &= (~0x7fffff);
// set top_mem registers to ram size
printk_spew("Setting top_mem to 0x%x\n", ram_megabytes);
rdmsr(TOP_MEM, lo, hi);
printk_spew("TOPMEM was 0x%02x:0x%02x\n", hi, lo);
hi = 0;
lo = ram_megabytes;
wrmsr(TOP_MEM, lo, hi);
// I am setting this even though I won't enable it
wrmsr(TOP_MEM2, lo, hi);
/* zero the IORR's before we enable to prevent
* undefined side effects
*/
lo = hi = 0;
for (i = IORR_FIRST; i <= IORR_LAST; i++)
wrmsr(i, lo, hi);
rdmsr(SYSCFG, lo, hi);
printk_spew("SYSCFG was 0x%x:0x%x\n", hi, lo);
lo |= MTRRVARDRAMEN;
wrmsr(SYSCFG, lo, hi);
rdmsr(SYSCFG, lo, hi);
printk_spew("SYSCFG IS NOW 0x%x:0x%x\n", hi, lo);
}

99
src/cpu/k8/earlymtrr.inc Normal file
View File

@ -0,0 +1,99 @@
#include <cpu/k8/mtrr.h>
/* The fixed and variable MTRRs are powered-up with random values, clear them to
* MTRR_TYPE_UNCACHABLE for safty reason
*/
earlymtrr_start:
xorl %eax, %eax # clear %eax and %edx
xorl %edx, %edx #
movl $fixed_mtrr_msr, %esi
clear_fixed_var_mtrr:
lodsl (%esi), %eax
testl %eax, %eax
jz clear_fixed_var_mtrr_out
movl %eax, %ecx
xorl %eax, %eax
wrmsr
jmp clear_fixed_var_mtrr
clear_fixed_var_mtrr_out:
/* enable memory access for 0 - 8MB using top_mem */
movl $TOP_MEM, %ecx
xorl %edx, %edx
movl $0x0800000, %eax
wrmsr
set_var_mtrr:
/* enable caching for 0 - 128MB using variable mtrr */
movl $0x200, %ecx
rdmsr
andl $0xfffffff0, %edx
orl $0x00000000, %edx
andl $0x00000f00, %eax
orl $0x00000006, %eax
wrmsr
movl $0x201, %ecx
rdmsr
andl $0xfffffff0, %edx
orl $0x0000000f, %edx
andl $0x000007ff, %eax
orl $0xf0000800, %eax
wrmsr
#if defined(XIP_ROM_SIZE) && defined(XIP_ROM_BASE)
/* enable write protect caching so we can do execute in place
* on the flash rom.
*/
movl $0x202, %ecx
xorl %edx, %edx
movl $(XIP_ROM_BASE | 0x005), %eax
wrmsr
movl $0x203, %ecx
movl $0x0000000f, %edx
movl $(~(XIP_ROM_SIZE - 1) | 0x800), %eax
wrmsr
#endif /* XIP_ROM_SIZE && XIP_ROM_BASE */
enable_mtrr:
/* Set the default memory type and enable fixed and variable MTRRs */
movl $0x2ff, %ecx
xorl %edx, %edx
/* Enable Variable MTRRs */
movl $0x00000800, %eax
wrmsr
/* Enable the MTRRs in SYSCFG */
movl $SYSCFG_MSR, %ecx
rdmsr
orl $(SYSCFG_MSR_MtrrVarDramEn), %eax
wrmsr
/* enable cache */
movl %cr0, %eax
andl $0x9fffffff,%eax
movl %eax, %cr0
jmp earlymtrr_end
fixed_mtrr_msr:
.long 0x250, 0x258, 0x259
.long 0x268, 0x269, 0x26A
.long 0x26B, 0x26C, 0x26D
.long 0x26E, 0x26F
var_mtrr_msr:
.long 0x200, 0x201, 0x202, 0x203
.long 0x204, 0x205, 0x206, 0x207
.long 0x208, 0x209, 0x20A, 0x20B
.long 0x20C, 0x20D, 0x20E, 0x20F
var_iorr_msr:
.long 0xC0010016, 0xC0010017, 0xC0010018, 0xC0010019
mem_top:
.long 0xC001001A, 0xC001001D
.long 0x000 /* NULL, end of table */
earlymtrr_end:

222
src/cpu/p5/cpuid.c Normal file
View File

@ -0,0 +1,222 @@
#ifndef lint
static char rcsid[] = "$Id$";
#endif
#include <console/console.h>
#include <cpu/p5/cpuid.h>
#ifdef i586
#include <cpu/p6/msr.h>
#endif
int mtrr_check(void)
{
#ifdef i686
/* Only Pentium Pro and later have MTRR */
unsigned long low, high;
printk_debug("\nMTRR check\n");
rdmsr(0x2ff, low, high);
low = low >> 10;
printk_debug("Fixed MTRRs : ");
if (low & 0x01)
printk_debug("Enabled\n");
else
printk_debug("Disabled\n");
printk_debug("Variable MTRRs: ");
if (low & 0x02)
printk_debug("Enabled\n");
else
printk_debug("Disabled\n");
printk_debug("\n");
post_code(0x93);
return ((int) low);
#else /* !i686 */
return 0;
#endif /* i686 */
}
void display_cpuid(void)
{
int op, eax, ebx, ecx, edx;
int max_op;
max_op = 0;
printk_debug("\n");
for (op = 0; op <= max_op; op++) {
cpuid(op, &eax, &ebx, &ecx, &edx);
if (0 == op) {
max_op = eax;
printk_debug("Max cpuid index : %d\n", eax);
printk_debug("Vendor ID : "
"%c%c%c%c%c%c%c%c%c%c%c%c\n",
ebx, ebx >> 8, ebx >> 16, ebx >> 24, edx,
edx >> 8, edx >> 16, edx >> 24, ecx, ecx >> 8,
ecx >> 16, ecx >> 24);
} else if (1 == op) {
printk_debug("Processor Type : 0x%02x\n",
(eax >> 12) & 0x03);
printk_debug("Processor Family : 0x%02x\n",
(eax >> 8) & 0x0f);
printk_debug("Processor Model : 0x%02x\n",
(eax >> 4) & 0x0f);
printk_debug("Processor Mask : 0x%02x\n",
(ecx >> 0) & 0x0f);
printk_debug("Processor Stepping : 0x%02x\n",
(eax >> 0) & 0x0f);
printk_debug("Feature flags : 0x%08x\n", edx);
} else if (2 == op) {
int desc[4];
int ii;
int _desc;
printk_debug("\n");
printk_debug("Cache/TLB descriptor values: %d "
"reads required\n", eax & 0xff);
desc[0] = eax;
desc[1] = ebx;
desc[2] = ecx;
desc[3] = edx;
for (ii = 1; ii < 16; ii++) {
if (desc[ii >> 2] & 0x80000000) {
printk_debug("reserved descriptor\n");
continue;
}
_desc =
((desc[ii >> 2]) >> ((ii & 0x3) << 3))
& 0xff;
printk_debug("Desc 0x%02x : ", _desc);
switch (_desc) {
case 0x00:
printk_debug("null\n");
break;
case 0x01:
printk_debug("Instr TLB: "
"4KB pages, "
"4-way set assoc, "
"32 entries\n");
break;
case 0x02:
printk_debug("Instr TLB: "
"4MB pages, "
"fully assoc, " "2 entries\n");
break;
case 0x03:
printk_debug("Data TLB: "
"4KB pages, "
"4-way set assoc, "
"64 entries\n");
break;
case 0x04:
printk_debug("Data TLB: "
"4MB pages, "
"4-way set assoc, "
"8 entries\n");
break;
case 0x06:
printk_debug("Inst cache: "
"8K bytes, "
"4-way set assoc, "
"32 byte line size\n");
break;
case 0x08:
printk_debug("Inst cache: "
"16K bytes, "
"4-way set assoc, "
"32 byte line size\n");
break;
case 0x0a:
printk_debug("Data cache: "
"8K bytes, "
"2-way set assoc, "
"32 byte line size\n");
break;
case 0x0c:
printk_debug("Data cache: "
"16K bytes, "
"2-way or 4-way set assoc, "
"32 byte line size\n");
break;
case 0x40:
printk_debug("No L2 cache\n");
break;
case 0x41:
printk_debug("L2 Unified cache: "
"128K bytes, "
"4-way set assoc, "
"32 byte line size\n");
break;
case 0x42:
printk_debug("L2 Unified cache: "
"256K bytes, "
"4-way set assoc, "
"32 byte line size\n");
break;
case 0x43:
printk_debug("L2 Unified cache: "
"512K bytes, "
"4-way set assoc, "
"32 byte line size\n");
break;
case 0x44:
printk_debug("L2 Unified cache: "
"1M byte, "
"4-way set assoc, "
"32 byte line size\n");
break;
case 0x45:
printk_debug("L2 Unified cache: "
"2M byte, "
"4-way set assoc, "
"32 byte line size\n");
break;
case 0x82:
printk_debug("L2 Unified cache: "
"256K bytes, "
"8-way set assoc, "
"32 byte line size\n");
break;
default:
printk_debug("UNKNOWN\n");
}
}
printk_debug("\n");
} else {
printk_debug("op: 0x%02x eax:0x%08x "
"ebx:0x%08x ecx:0x%08x edx:0x%08x\n",
op, eax, ebx, ecx, edx);
}
}
printk_debug("\n");
post_code(0x92);
}

356
src/cpu/p6/mtrr.c Normal file
View File

@ -0,0 +1,356 @@
/*
* intel_mtrr.c: setting MTRR to decent values for cache initialization on P6
*
* Derived from intel_set_mtrr in intel_subr.c and mtrr.c in linux kernel
*
* Copyright 2000 Silicon Integrated System Corporation
*
* 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.
*
*
* Reference: Intel Architecture Software Developer's Manual, Volume 3: System Programming
*
* $Id$
*/
#ifndef lint
static char rcsid[] = "$Id$";
#endif
#include <console/console.h>
#include <mem.h>
#include <cpu/p6/msr.h>
#include <cpu/p6/mtrr.h>
#include <cpu/k7/mtrr.h>
#define arraysize(x) (sizeof(x)/sizeof((x)[0]))
static unsigned int mtrr_msr[] = {
MTRRfix64K_00000_MSR, MTRRfix16K_80000_MSR, MTRRfix16K_A0000_MSR,
MTRRfix4K_C0000_MSR, MTRRfix4K_C8000_MSR, MTRRfix4K_D0000_MSR, MTRRfix4K_D8000_MSR,
MTRRfix4K_E0000_MSR, MTRRfix4K_E8000_MSR, MTRRfix4K_F0000_MSR, MTRRfix4K_F8000_MSR,
};
static void intel_enable_fixed_mtrr(void)
{
unsigned long low, high;
rdmsr(MTRRdefType_MSR, low, high);
low |= 0xc00;
wrmsr(MTRRdefType_MSR, low, high);
}
static void intel_enable_var_mtrr(void)
{
unsigned long low, high;
rdmsr(MTRRdefType_MSR, low, high);
low |= 0x800;
wrmsr(MTRRdefType_MSR, low, high);
}
static inline void disable_cache(void)
{
unsigned int tmp;
/* Disable cache */
/* Write back the cache and flush TLB */
asm volatile (
"movl %%cr0, %0\n\t"
"orl $0x40000000, %0\n\t"
"wbinvd\n\t"
"movl %0, %%cr0\n\t"
"wbinvd\n\t"
:"=r" (tmp)
::"memory");
}
static inline void enable_cache(void)
{
unsigned int tmp;
// turn cache back on.
asm volatile (
"movl %%cr0, %0\n\t"
"andl $0x9fffffff, %0\n\t"
"movl %0, %%cr0\n\t"
:"=r" (tmp)
::"memory");
}
/* setting variable mtrr, comes from linux kernel source */
static void intel_set_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek, unsigned char type)
{
unsigned long base_high, base_low;
unsigned long mask_high, mask_low;
base_high = basek >> 22;
base_low = basek << 10;
if (sizek < 4*1024*1024) {
mask_high = 0x0F;
mask_low = ~((sizek << 10) -1);
}
else {
mask_high = 0x0F & (~((sizek >> 22) -1));
mask_low = 0;
}
if (reg >= 8)
return;
// it is recommended that we disable and enable cache when we
// do this.
disable_cache();
if (sizek == 0) {
/* The invalid bit is kept in the mask, so we simply clear the
relevant mask register to disable a range. */
wrmsr (MTRRphysMask_MSR (reg), 0, 0);
} else {
/* Bit 32-35 of MTRRphysMask should be set to 1 */
wrmsr (MTRRphysBase_MSR(reg), base_low | type, base_high);
wrmsr (MTRRphysMask_MSR(reg), mask_low | 0x800, mask_high);
}
enable_cache();
}
/* setting variable mtrr, comes from linux kernel source */
void set_var_mtrr(unsigned int reg, unsigned long base, unsigned long size, unsigned char type)
{
unsigned int tmp;
if (reg >= 8)
return;
// it is recommended that we disable and enable cache when we
// do this.
disable_cache();
if (size == 0) {
/* The invalid bit is kept in the mask, so we simply clear the
relevant mask register to disable a range. */
wrmsr (MTRRphysMask_MSR (reg), 0, 0);
} else {
/* Bit 32-35 of MTRRphysMask should be set to 1 */
wrmsr (MTRRphysBase_MSR (reg), base | type, 0);
wrmsr (MTRRphysMask_MSR (reg), ~(size - 1) | 0x800, 0x0F);
}
// turn cache back on.
enable_cache();
}
/* fms: find most sigificant bit set, stolen from Linux Kernel Source. */
static inline unsigned int fms(unsigned int x)
{
int r;
__asm__("bsrl %1,%0\n\t"
"jnz 1f\n\t"
"movl $0,%0\n"
"1:" : "=r" (r) : "g" (x));
return r;
}
/* fms: find least sigificant bit set */
static inline unsigned int fls(unsigned int x)
{
int r;
__asm__("bsfl %1,%0\n\t"
"jnz 1f\n\t"
"movl $32,%0\n"
"1:" : "=r" (r) : "g" (x));
return r;
}
/* setting up variable and fixed mtrr
*
* From Intel Vol. III Section 9.12.4, the Range Size and Base Alignment has some kind of requirement:
* 1. The range size must be 2^N byte for N >= 12 (i.e 4KB minimum).
* 2. The base address must be 2^N aligned, where the N here is equal to the N in previous
* requirement. So a 8K range must be 8K aligned not 4K aligned.
*
* These requirement is meet by "decompositing" the ramsize into Sum(Cn * 2^n, n = [0..N], Cn = [0, 1]).
* For Cm = 1, there is a WB range of 2^m size at base address Sum(Cm * 2^m, m = [N..n]).
* A 124MB (128MB - 4MB SMA) example:
* ramsize = 124MB == 64MB (at 0MB) + 32MB (at 64MB) + 16MB (at 96MB ) + 8MB (at 112MB) + 4MB (120MB).
* But this wastes a lot of MTRR registers so we use another more "aggresive" way with Uncacheable Regions.
*
* In the Uncacheable Region scheme, we try to cover the whole ramsize by one WB region as possible,
* If (an only if) this can not be done we will try to decomposite the ramesize, the mathematical formula
* whould be ramsize = Sum(Cn * 2^n, n = [0..N], Cn = [-1, 0, 1]). For Cn = -1, a Uncachable Region is used.
* The same 124MB example:
* ramsize = 124MB == 128MB WB (at 0MB) + 4MB UC (at 124MB)
* or a 156MB (128MB + 32MB - 4MB SMA) example:
* ramsize = 156MB == 128MB WB (at 0MB) + 32MB WB (at 128MB) + 4MB UC (at 156MB)
*/
/* 2 MTRRS are reserved for the operating system */
#define BIOS_MTRRS 6
#define OS_MTRRS 2
#define MTRRS (BIOS_MTRRS + OS_MTRRS)
static void set_fixed_mtrrs(unsigned int first, unsigned int last, unsigned char type)
{
unsigned int i;
unsigned int fixed_msr = NUM_FIXED_RANGES >> 3;
unsigned long low, high;
low = high = 0; /* Shut up gcc */
for(i = first; i < last; i++) {
/* When I switch to a new msr read it in */
if (fixed_msr != i >> 3) {
/* But first write out the old msr */
if (fixed_msr < (NUM_FIXED_RANGES >> 3)) {
disable_cache();
wrmsr(mtrr_msr[fixed_msr], low, high);
enable_cache();
}
fixed_msr = i>>3;
rdmsr(mtrr_msr[fixed_msr], low, high);
}
if ((i & 7) < 4) {
low &= ~(0xff << ((i&3)*8));
low |= type << ((i&3)*8);
} else {
high &= ~(0xff << ((i&3)*8));
high |= type << ((i&3)*8);
}
}
/* Write out the final msr */
if (fixed_msr < (NUM_FIXED_RANGES >> 3)) {
disable_cache();
wrmsr(mtrr_msr[fixed_msr], low, high);
enable_cache();
}
}
static unsigned fixed_mtrr_index(unsigned long addrk)
{
unsigned index;
index = (addrk - 0) >> 6;
if (index >= 8) {
index = ((addrk - 8*64) >> 4) + 8;
}
if (index >= 24) {
index = ((addrk - (8*64 + 16*16)) >> 2) + 24;
}
if (index > NUM_FIXED_RANGES) {
index = NUM_FIXED_RANGES;
}
return index;
}
static unsigned int range_to_mtrr(unsigned int reg,
unsigned long range_startk, unsigned long range_sizek,
unsigned long next_range_startk)
{
if (!range_sizek || (reg >= BIOS_MTRRS)) {
return reg;
}
while(range_sizek) {
unsigned long max_align, align;
unsigned long sizek;
/* Compute the maximum size I can make a range */
max_align = fls(range_startk);
align = fms(range_sizek);
if (align > max_align) {
align = max_align;
}
sizek = 1 << align;
printk_debug("Setting variable MTRR %d, base: %4dMB, range: %4dMB, type WB\n",
reg, range_startk >>10, sizek >> 10);
intel_set_var_mtrr(reg++, range_startk, sizek, MTRR_TYPE_WRBACK);
range_startk += sizek;
range_sizek -= sizek;
if (reg >= BIOS_MTRRS)
break;
}
return reg;
}
void setup_mtrrs(struct mem_range *mem)
{
/* Try this the simple way of incrementally adding together
* mtrrs. If this doesn't work out we can get smart again
* and clear out the mtrrs.
*/
struct mem_range *memp;
unsigned long range_startk, range_sizek;
unsigned int reg;
printk_debug("\n");
/* Initialized the fixed_mtrrs to uncached */
printk_debug("Setting fixed MTRRs(%d-%d) type: UC\n",
0, NUM_FIXED_RANGES);
set_fixed_mtrrs(0, NUM_FIXED_RANGES, MTRR_TYPE_UNCACHABLE);
/* Now see which of the fixed mtrrs cover ram.
*/
for(memp = mem; memp->sizek; memp++) {
unsigned int start_mtrr;
unsigned int last_mtrr;
start_mtrr = fixed_mtrr_index(memp->basek);
last_mtrr = fixed_mtrr_index(memp->basek + memp->sizek);
if (start_mtrr >= NUM_FIXED_RANGES) {
break;
}
printk_debug("Setting fixed MTRRs(%d-%d) type: WB\n",
start_mtrr, last_mtrr);
set_fixed_mtrrs(start_mtrr, last_mtrr, MTRR_TYPE_WRBACK);
}
printk_debug("DONE fixed MTRRs\n");
/* Cache as many memory areas as possible */
/* FIXME is there an algorithm for computing the optimal set of mtrrs?
* In some cases it is definitely possible to do better.
*/
range_startk = 0;
range_sizek = 0;
reg = 0;
for (memp = mem; memp->sizek; memp++) {
/* See if I can merge with the last range
* Either I am below 1M and the fixed mtrrs handle it, or
* the ranges touch.
*/
if ((memp->basek <= 1024) || (range_startk + range_sizek == memp->basek)) {
unsigned long endk = memp->basek + memp->sizek;
range_sizek = endk - range_startk;
continue;
}
/* Write the range mtrrs */
if (range_sizek != 0) {
reg = range_to_mtrr(reg, range_startk, range_sizek, memp->basek);
range_startk = 0;
range_sizek = 0;
if (reg >= BIOS_MTRRS)
break;
}
/* Allocate an msr */
range_startk = memp->basek;
range_sizek = memp->sizek;
}
/* Write the last range */
reg = range_to_mtrr(reg, range_startk, range_sizek, 0);
printk_debug("DONE variable MTRRs\n");
printk_debug("Clear out the extra MTRR's\n");
/* Clear out the extra MTRR's */
while(reg < MTRRS) {
intel_set_var_mtrr(reg++, 0, 0, 0);
}
/* enable fixed MTRR */
printk_debug("call intel_enable_fixed_mtrr()\n");
intel_enable_fixed_mtrr();
printk_debug("call intel_enable_var_mtrr()\n");
intel_enable_var_mtrr();
printk_debug("Leave %s\n", __FUNCTION__);
}

423
src/devices/device.c Normal file
View File

@ -0,0 +1,423 @@
/*
* (c) 1999--2000 Martin Mares <mj@suse.cz>
* (c) 2003 Eric Biederman <ebiederm@xmission.com>
*/
/* lots of mods by ron minnich (rminnich@lanl.gov), with
* the final architecture guidance from Tom Merritt (tjm@codegen.com)
* In particular, we changed from the one-pass original version to
* Tom's recommended multiple-pass version. I wasn't sure about doing
* it with multiple passes, until I actually started doing it and saw
* the wisdom of Tom's recommendations ...
*
* Lots of cleanups by Eric Biederman to handle bridges, and to
* handle resource allocation for non-pci devices.
*/
#include <console/console.h>
#include <bitops.h>
#include <device.h>
#include <arch/io.h>
#include <pci.h>
/**
* This is the root of the device tree. A PCI tree always has
* one bus, bus 0. Bus 0 contains devices and bridges.
*/
struct device dev_root;
/* Linked list of ALL devices */
struct device *all_devices = 0;
/* pointer to the last device */
static struct device **last_dev_p = &all_devices;
#define DEVICE_MEM_HIGH 0xFEC00000UL /* Reserve 20M for the system */
#define DEVICE_IO_START 0x1000
unsigned long device_memory_base;
/* Append a new device to the global device chain.
* The chain is used to find devices once everything is set up.
*/
void append_device(struct device *dev)
{
*last_dev_p = dev;
last_dev_p = &dev->next;
}
/** round a number to an alignment.
* @param val the starting value
* @param roundup Alignment as a power of two
* @returns rounded up number
*/
static unsigned long round(unsigned long val, unsigned long roundup)
{
/* ROUNDUP MUST BE A POWER OF TWO. */
unsigned long inverse;
inverse = ~(roundup - 1);
val += (roundup - 1);
val &= inverse;
return val;
}
static unsigned long round_down(unsigned long val, unsigned long round_down)
{
/* ROUND_DOWN MUST BE A POWER OF TWO. */
unsigned long inverse;
inverse = ~(round_down - 1);
val &= inverse;
return val;
}
/** Read the resources on all devices of a given bus.
* @param bus bus to read the resources on.
*/
static void read_resources(struct device *bus)
{
struct device *curdev;
/* Walk through all of the devices and find which resources they need. */
for(curdev = bus->children; curdev; curdev = curdev->sibling) {
if (curdev->resources > 0) {
continue;
}
curdev->ops->read_resources(curdev);
}
}
static struct device *largest_resource(struct device *bus, struct resource **result_res,
unsigned long type_mask, unsigned long type)
{
struct device *curdev;
struct device *result_dev = 0;
struct resource *last = *result_res;
struct resource *result = 0;
int seen_last = 0;
for(curdev = bus->children; curdev; curdev = curdev->sibling) {
int i;
for(i = 0; i < curdev->resources; i++) {
struct resource *resource = &curdev->resource[i];
/* If it isn't the right kind of resource ignore it */
if ((resource->flags & type_mask) != type) {
continue;
}
/* Be certain to pick the successor to last */
if (resource == last) {
seen_last = 1;
continue;
}
if (last && (
(last->align < resource->align) ||
((last->align == resource->align) &&
(last->size < resource->size)) ||
((last->align == resource->align) &&
(last->size == resource->size) &&
(!seen_last)))) {
continue;
}
if (!result ||
(result->align < resource->align) ||
((result->align == resource->align) &&
(result->size < resource->size))) {
result_dev = curdev;
result = resource;
}
}
}
*result_res = result;
return result_dev;
}
/* Compute allocate resources is the guts of the resource allocator.
*
* The problem.
* - Allocate resources locations for every device.
* - Don't overlap, and follow the rules of bridges.
* - Don't overlap with resources in fixed locations.
* - Be efficient so we don't have ugly strategies.
*
* The strategy.
* - Devices that have fixed addresses are the minority so don't
* worry about them too much. Instead only use part of the address
* space for devices with programmable addresses. This easily handles
* everything except bridges.
*
* - PCI devices are required to have thier sizes and their alignments
* equal. In this case an optimal solution to the packing problem
* exists. Allocate all devices from highest alignment to least
* alignment or vice versa. Use this.
*
* - So we can handle more than PCI run two allocation passes on
* bridges. The first to see how large the resources are behind
* the bridge, and what their alignment requirements are. The
* second to assign a safe address to the devices behind the
* bridge. This allows me to treat a bridge as just a device with
* a couple of resources, and not need to special case it in the
* allocator. Also this allows handling of other types of bridges.
*
*/
void compute_allocate_resource(
struct device *bus,
struct resource *bridge,
unsigned long type_mask,
unsigned long type)
{
struct device *dev;
struct resource *resource;
unsigned long base;
unsigned long align, min_align;
min_align = 0;
base = bridge->base;
/* We want different minimum alignments for different kinds of
* resources. These minimums are not device type specific
* but resource type specific.
*/
if (bridge->flags & IORESOURCE_IO) {
min_align = log2(DEVICE_IO_ALIGN);
}
if (bridge->flags & IORESOURCE_MEM) {
min_align = log2(DEVICE_MEM_ALIGN);
}
printk_spew("DEV: %02x:%02x.%01x compute_allocate_%s: base: %08lx size: %08lx align: %d gran: %d\n",
bus->bus->secondary,
PCI_SLOT(bus->devfn), PCI_FUNC(bus->devfn),
(bridge->flags & IORESOURCE_IO)? "io":
(bridge->flags & IORESOURCE_PREFETCH)? "prefmem" : "mem",
base, bridge->size, bridge->align, bridge->gran);
/* Make certain I have read in all of the resources */
read_resources(bus);
/* Remember I haven't found anything yet. */
resource = 0;
/* Walk through all the devices on the current bus and compute the addresses */
while((dev = largest_resource(bus, &resource, type_mask, type))) {
unsigned long size;
/* Do NOT I repeat do not ignore resources which have zero size.
* If they need to be ignored dev->read_resources should not even
* return them. Some resources must be set even when they have
* no size. PCI bridge resources are a good example of this.
*/
/* Propogate the resource alignment to the bridge register */
if (resource->align > bridge->align) {
bridge->align = resource->align;
}
/* Make certain we are dealing with a good minimum size */
size = resource->size;
align = resource->align;
if (align < min_align) {
align = min_align;
}
if (resource->flags & IORESOURCE_IO) {
/* Don't allow potential aliases over the
* legacy pci expansion card addresses.
*/
if ((base > 0x3ff) && ((base & 0x300) != 0)) {
base = (base & ~0x3ff) + 0x400;
}
/* Don't allow allocations in the VGA IO range.
* PCI has special cases for that.
*/
else if ((base >= 0x3b0) && (base <= 0x3df)) {
base = 0x3e0;
}
}
if (((round(base, 1UL << align) + size) -1) <= resource->limit) {
/* base must be aligned to size */
base = round(base, 1UL << align);
resource->base = base;
resource->flags |= IORESOURCE_SET;
base += size;
printk_spew(
"DEV: %02x:%02x.%01x %02x * [0x%08lx - 0x%08lx] %s\n",
dev->bus->secondary,
PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
resource->index,
resource->base, resource->base + resource->size -1,
(resource->flags & IORESOURCE_IO)? "io":
(resource->flags & IORESOURCE_PREFETCH)? "prefmem": "mem");
}
}
/* A pci bridge resource does not need to be a power
* of two size, but it does have a minimum granularity.
* Round the size up to that minimum granularity so we
* know not to place something else at an address postitively
* decoded by the bridge.
*/
bridge->size = round(base, 1UL << bridge->gran) - bridge->base;
printk_spew("DEV: %02x:%02x.%01x compute_allocate_%s: base: %08lx size: %08lx align: %d gran: %d done\n",
bus->bus->secondary,
PCI_SLOT(bus->devfn), PCI_FUNC(bus->devfn),
(bridge->flags & IORESOURCE_IO)? "io":
(bridge->flags & IORESOURCE_PREFETCH)? "prefmem" : "mem",
base, bridge->size, bridge->align, bridge->gran);
}
static void allocate_vga_resource(void)
{
/* FIXME handle the VGA pallette snooping */
struct device *dev, *vga, *bus;
bus = vga = 0;
for(dev = all_devices; dev; dev = dev->next) {
uint32_t class_revision;
pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_revision);
if (((class_revision >> 24) == 0x03) &&
((class_revision >> 16) != 0x380)) {
if (!vga) {
printk_debug("Allocating VGA resource\n");
vga = dev;
}
if (vga == dev) {
/* All legacy VGA cards have MEM & I/O space registers */
dev->command |= PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
} else {
/* It isn't safe to enable other VGA cards */
dev->command &= ~(PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
}
}
}
if (vga) {
bus = vga->bus;
}
/* Now walk up the bridges setting the VGA enable */
while(bus) {
uint16_t ctrl;
pci_read_config_word(bus, PCI_BRIDGE_CONTROL, &ctrl);
ctrl |= PCI_BRIDGE_CTL_VGA;
pci_write_config_word(bus, PCI_BRIDGE_CONTROL, ctrl);
bus = (bus == bus->bus)? 0 : bus->bus;
}
}
/** Assign the computed resources to the bridges and devices on the bus.
* Recurse to any bridges found on this bus first. Then do the devices
* on this bus.
* @param bus Pointer to the structure for this bus
*/
void assign_resources(struct device *bus)
{
struct device *curdev;
printk_debug("ASSIGN RESOURCES, bus %d\n", bus->secondary);
for (curdev = bus->children; curdev; curdev = curdev->sibling) {
curdev->ops->set_resources(curdev);
}
printk_debug("ASSIGNED RESOURCES, bus %d\n", bus->secondary);
}
static void enable_resources(struct device *bus)
{
struct device *curdev;
/* Walk through the chain of all pci devices and enable them.
* This is effectively a breadth first traversal so we should
* not have enalbing ordering problems.
*/
for (curdev = all_devices; curdev; curdev = curdev->next) {
uint16_t command;
pci_read_config_word(curdev, PCI_COMMAND, &command);
command |= curdev->command;
printk_debug("DEV: %02x:%02x.%01x cmd <- %02x\n",
curdev->bus->secondary,
PCI_SLOT(curdev->devfn), PCI_FUNC(curdev->devfn),
command);
pci_write_config_word(curdev, PCI_COMMAND, command);
}
}
/** Enumerate the resources on the PCI by calling pci_init
*/
void dev_enumerate(void)
{
struct device *root;
printk_info("Enumerating buses...");
root = &dev_root;
if (!root->ops) {
root->ops = &default_pci_ops_root;
}
root->subordinate = root->ops->scan_bus(root, 0);
printk_info("done\n");
}
/** Starting at the root, compute what resources are needed and allocate them.
* I/O starts at PCI_IO_START. Since the assignment is hierarchical we
* set the values into the dev_root struct.
*/
void dev_configure(void)
{
struct device *root = &dev_root;
printk_info("Allocating resources...");
printk_debug("\n");
root->ops->read_resources(root);
/* Make certain the io devices are allocated somewhere
* safe.
*/
root->resource[0].base = DEVICE_IO_START;
root->resource[0].flags |= IORESOURCE_SET;
/* Now reallocate the pci resources memory with the
* highest addresses I can manage.
*/
root->resource[1].base =
round_down(DEVICE_MEM_HIGH - root->resource[1].size,
1UL << root->resource[1].align);
device_memory_base = root->resource[1].base;
root->resource[1].flags |= IORESOURCE_SET;
// now just set things into registers ... we hope ...
root->ops->set_resources(root);
allocate_vga_resource();
printk_info("done.\n");
}
/** Starting at the root, walk the tree and enable all devices/bridges.
* What really happens is computed COMMAND bits get set in register 4
*/
void dev_enable(void)
{
printk_info("Enabling resourcess...");
/* now enable everything. */
enable_resources(&dev_root);
printk_info("done.\n");
}
/** Starting at the root, walk the tree and call a driver to
* do device specific setup.
*/
void dev_initialize(void)
{
struct device *dev;
printk_info("Initializing devices...\n");
for (dev = all_devices; dev; dev = dev->next) {
if (dev->ops->init) {
printk_debug("PCI: %02x:%02x.%01x init\n",
dev->bus->secondary,
PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
dev->ops->init(dev);
}
}
printk_info("Devices initialized\n");
}

56
src/devices/device_util.c Normal file
View File

@ -0,0 +1,56 @@
#include <console/console.h>
#include <device.h>
/**
* Given a bus and a devfn number, find the device structure
* @param bus The bus number
* @param devfn a device/function number
* @return pointer to the device structure
*/
struct device *dev_find_slot(unsigned int bus, unsigned int devfn)
{
struct device *dev;
for (dev = all_devices; dev; dev = dev->next)
if (dev->bus->secondary == bus && dev->devfn == devfn)
break;
return dev;
}
/** Find a device of a given vendor and type
* @param vendor Vendor ID (e.g. 0x8086 for Intel)
* @param device Device ID
* @param from Pointer to the device structure, used as a starting point
* in the linked list of all_devices, which can be 0 to start at the
* head of the list (i.e. all_devices)
* @return Pointer to the device struct
*/
struct device *dev_find_device(unsigned int vendor, unsigned int device, struct device *from)
{
if (!from)
from = all_devices;
else
from = from->next;
while (from && (from->vendor != vendor || from->device != device))
from = from->next;
return from;
}
/** Find a device of a given class
* @param class Class of the device
* @param from Pointer to the device structure, used as a starting point
* in the linked list of all_devices, which can be 0 to start at the
* head of the list (i.e. all_devices)
* @return Pointer to the device struct
*/
struct device *dev_find_class(unsigned int class, struct device *from)
{
if (!from)
from = all_devices;
else
from = from->next;
while (from && from->class != class)
from = from->next;
return from;
}

670
src/devices/pci_device.c Normal file
View File

@ -0,0 +1,670 @@
/*
* PCI Bus Services, see include/linux/pci.h for further explanation.
*
* Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter,
* David Mosberger-Tang
*
* Copyright 1997 -- 1999 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
*
* Copyright 2003 -- Eric Biederman <ebiederman@lnxi.com>
*/
#include <console/console.h>
#include <stdlib.h>
#include <stdint.h>
#include <bitops.h>
#include <pci.h>
#include <pci_ids.h>
#include <string.h>
static unsigned int pci_scan_bridge(struct device *bus, unsigned int max);
/** Given a device and register, read the size of the BAR for that register.
* @param dev Pointer to the device structure
* @param resource Pointer to the resource structure
* @param index Address of the pci configuration register
*/
static void pci_get_resource(struct device *dev, struct resource *resource, unsigned long index)
{
uint32_t addr, size, base;
unsigned long type;
/* Initialize the resources to nothing */
resource->base = 0;
resource->size = 0;
resource->align = 0;
resource->gran = 0;
resource->limit = 0;
resource->flags = 0;
resource->index = index;
pci_read_config_dword(dev, index, &addr);
if (addr == 0xffffffffUL)
return;
/* FIXME: more consideration for 64-bit PCI devices,
* we currently detect their size but otherwise
* treat them as 32-bit resources
*/
/* get the size */
pci_write_config_dword(dev, index, ~0);
pci_read_config_dword(dev, index, &size);
/* get the minimum value the bar can be set to */
pci_write_config_dword(dev, index, 0);
pci_read_config_dword(dev, index, &base);
/* restore addr */
pci_write_config_dword(dev, index, addr);
/*
* some broken hardware has read-only registers that do not
* really size correctly. You can tell this if addr == size
* Example: the acer m7229 has BARs 1-4 normally read-only.
* so BAR1 at offset 0x10 reads 0x1f1. If you size that register
* by writing 0xffffffff to it, it will read back as 0x1f1 -- a
* violation of the spec.
* We catch this case and ignore it by settting size and type to 0.
* This incidentally catches the common case where registers
* read back as 0 for both address and size.
*/
if ((addr == size) && (addr == base)) {
if (size != 0) {
printk_debug(
"PCI: %02x:%02x.%01x register %02x(%08x), read-only ignoring it\n",
dev->bus->secondary,
PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
index, addr);
}
resource->flags = 0;
}
/* Now compute the actual size, See PCI Spec 6.2.5.1 ... */
else if (size & PCI_BASE_ADDRESS_SPACE_IO) {
type = size & (~PCI_BASE_ADDRESS_IO_MASK);
/* BUG! Top 16 bits can be zero (or not)
* So set them to 0xffff so they go away ...
*/
resource->size = (~((size | 0xffff0000) & PCI_BASE_ADDRESS_IO_MASK)) +1;
resource->align = log2(resource->size);
resource->gran = resource->align;
resource->flags = IORESOURCE_IO;
resource->limit = 0xffff;
}
else {
/* A Memory mapped base address */
type = size & (~PCI_BASE_ADDRESS_MEM_MASK);
resource->size = (~(size &PCI_BASE_ADDRESS_MEM_MASK)) +1;
resource->align = log2(resource->size);
resource->gran = resource->align;
resource->flags = IORESOURCE_MEM;
if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) {
resource->flags |= IORESOURCE_PREFETCH;
}
type &= PCI_BASE_ADDRESS_MEM_TYPE_MASK;
if (type == PCI_BASE_ADDRESS_MEM_TYPE_32) {
/* 32bit limit */
resource->limit = 0xffffffffUL;
}
else if (type == PCI_BASE_ADDRESS_MEM_TYPE_1M) {
/* 1MB limit */
resource->limit = 0x000fffffUL;
}
else if (type == PCI_BASE_ADDRESS_MEM_TYPE_64) {
unsigned long index_hi;
/* 64bit limit
* For now just treat this as a 32bit limit
*/
index_hi = index + 4;
resource->limit = 0xffffffffUL;
resource->flags |= IORESOURCE_PCI64;
pci_read_config_dword( dev, index_hi, &addr);
/* get the extended size */
pci_write_config_dword(dev, index_hi, 0xffffffffUL);
pci_read_config_dword( dev, index_hi, &size);
/* get the minimum value the bar can be set to */
pci_write_config_dword(dev, index_hi, 0);
pci_read_config_dword(dev, index_hi, &base);
/* restore addr */
pci_write_config_dword(dev, index_hi, addr);
if ((size == 0xffffffff) && (base == 0)) {
/* Clear the top half of the bar */
pci_write_config_dword(dev, index_hi, 0);
}
else {
printk_err("PCI: %02x:%02x.%01x Unable to handle 64-bit address\n",
dev->bus->secondary,
PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
resource->flags = IORESOURCE_PCI64;
}
}
else {
/* Invalid value */
resource->flags = 0;
}
}
/* dev->size holds the flags... */
return;
}
/** Read the base address registers for a given device.
* @param dev Pointer to the dev structure
* @param howmany How many registers to read (6 for device, 2 for bridge)
*/
static void pci_read_bases(struct device *dev, unsigned int howmany)
{
unsigned int reg;
unsigned long index;
reg = dev->resources;
for(index = PCI_BASE_ADDRESS_0;
(reg < MAX_RESOURCES) && (index < PCI_BASE_ADDRESS_0 + (howmany << 2)); ) {
struct resource *resource;
resource = &dev->resource[reg];
pci_get_resource(dev, resource, index);
reg += (resource->flags & (IORESOURCE_IO | IORESOURCE_MEM))? 1:0;
index += (resource->flags & IORESOURCE_PCI64)?8:4;
}
dev->resources = reg;
}
static void pci_bridge_read_bases(struct device *dev)
{
unsigned int reg = dev->resources;
/* FIXME handle bridges without some of the optional resources */
/* Initialize the io space constraints on the current bus */
dev->resource[reg].base = 0;
dev->resource[reg].size = 0;
dev->resource[reg].align = log2(PCI_IO_BRIDGE_ALIGN);
dev->resource[reg].gran = log2(PCI_IO_BRIDGE_ALIGN);
dev->resource[reg].limit = 0xffffUL;
dev->resource[reg].flags = IORESOURCE_IO | IORESOURCE_PCI_BRIDGE;
dev->resource[reg].index = PCI_IO_BASE;
compute_allocate_resource(dev, &dev->resource[reg],
IORESOURCE_IO, IORESOURCE_IO);
reg++;
/* Initiliaze the prefetchable memory constraints on the current bus */
dev->resource[reg].base = 0;
dev->resource[reg].size = 0;
dev->resource[reg].align = log2(PCI_MEM_BRIDGE_ALIGN);
dev->resource[reg].gran = log2(PCI_MEM_BRIDGE_ALIGN);
dev->resource[reg].limit = 0xffffffffUL;
dev->resource[reg].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_PCI_BRIDGE;
dev->resource[reg].index = PCI_PREF_MEMORY_BASE;
compute_allocate_resource(dev, &dev->resource[reg],
IORESOURCE_MEM | IORESOURCE_PREFETCH,
IORESOURCE_MEM | IORESOURCE_PREFETCH);
reg++;
/* Initialize the memory resources on the current bus */
dev->resource[reg].base = 0;
dev->resource[reg].size = 0;
dev->resource[reg].align = log2(PCI_MEM_BRIDGE_ALIGN);
dev->resource[reg].gran = log2(PCI_MEM_BRIDGE_ALIGN);
dev->resource[reg].limit = 0xffffffffUL;
dev->resource[reg].flags = IORESOURCE_MEM | IORESOURCE_PCI_BRIDGE;
dev->resource[reg].index = PCI_MEMORY_BASE;
compute_allocate_resource(dev, &dev->resource[reg],
IORESOURCE_MEM | IORESOURCE_PREFETCH,
IORESOURCE_MEM);
reg++;
dev->resources = reg;
}
static void pci_dev_read_resources(struct device *dev)
{
uint32_t addr;
dev->resources = 0;
memset(&dev->resource[0], 0, sizeof(dev->resource));
pci_read_bases(dev, 6);
pci_read_config_dword(dev, PCI_ROM_ADDRESS, &addr);
dev->rom_address = (addr == 0xffffffff)? 0 : addr;
}
static void pci_bus_read_resources(struct device *dev)
{
uint32_t addr;
dev->resources = 0;
memset(&dev->resource[0], 0, sizeof(dev->resource));
pci_bridge_read_bases(dev);
pci_read_bases(dev, 2);
pci_read_config_dword(dev, PCI_ROM_ADDRESS1, &addr);
dev->rom_address = (addr == 0xffffffff)? 0 : addr;
}
static void pci_set_resource(struct device *dev, struct resource *resource)
{
unsigned long base, limit;
unsigned long bridge_align = PCI_MEM_BRIDGE_ALIGN;
unsigned char buf[10];
/* Make certain the resource has actually been set */
if (!(resource->flags & IORESOURCE_SET)) {
#if 1
printk_err("ERROR: %02x:%02x.%01x %02x not allocated\n",
dev->bus->secondary,
PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
resource->index);
#endif
return;
}
/* Only handle PCI memory and IO resources for now */
if (!(resource->flags & (IORESOURCE_MEM |IORESOURCE_IO)))
return;
if (resource->flags & IORESOURCE_MEM) {
dev->command |= PCI_COMMAND_MEMORY;
bridge_align = PCI_MEM_BRIDGE_ALIGN;
}
if (resource->flags & IORESOURCE_IO) {
dev->command |= PCI_COMMAND_IO;
bridge_align = PCI_IO_BRIDGE_ALIGN;
}
if (resource->flags & IORESOURCE_PCI_BRIDGE) {
dev->command |= PCI_COMMAND_MASTER;
}
/* Get the base address */
base = resource->base;
/* Get the limit (rounded up) */
limit = base + ((resource->size + bridge_align - 1UL) & ~(bridge_align -1)) -1UL;
if (!(resource->flags & IORESOURCE_PCI_BRIDGE)) {
/*
* some chipsets allow us to set/clear the IO bit.
* (e.g. VIA 82c686a.) So set it to be safe)
*/
limit = base + resource->size -1;
if (resource->flags & IORESOURCE_IO) {
base |= PCI_BASE_ADDRESS_SPACE_IO;
}
pci_write_config_dword(dev, resource->index, base & 0xffffffff);
if (resource->flags & IORESOURCE_PCI64) {
/* FIXME handle real 64bit base addresses */
pci_write_config_dword(dev, resource->index + 4, 0);
}
}
else if (resource->index == PCI_IO_BASE) {
/* set the IO ranges
* WARNING: we don't really do 32-bit addressing for IO yet!
*/
compute_allocate_resource(dev, resource,
IORESOURCE_IO, IORESOURCE_IO);
pci_write_config_byte(dev, PCI_IO_BASE, base >> 8);
pci_write_config_byte(dev, PCI_IO_LIMIT, limit >> 8);
}
else if (resource->index == PCI_MEMORY_BASE) {
/* set the memory range
*/
compute_allocate_resource(dev, resource,
IORESOURCE_MEM | IORESOURCE_PREFETCH,
IORESOURCE_MEM);
pci_write_config_word(dev, PCI_MEMORY_BASE, base >> 16);
pci_write_config_word(dev, PCI_MEMORY_LIMIT, limit >> 16);
}
else if (resource->index == PCI_PREF_MEMORY_BASE) {
/* set the prefetchable memory range
* WARNING: we don't really do 64-bit addressing for prefetchable memory yet!
*/
compute_allocate_resource(dev, resource,
IORESOURCE_MEM | IORESOURCE_PREFETCH,
IORESOURCE_MEM | IORESOURCE_PREFETCH);
pci_write_config_word(dev, PCI_PREF_MEMORY_BASE, base >> 16);
pci_write_config_word(dev, PCI_PREF_MEMORY_LIMIT, limit >> 16);
}
else {
printk_err("ERROR: invalid resource->index %x\n",
resource->index);
}
buf[0] = '\0';
if (resource->flags & IORESOURCE_PCI_BRIDGE) {
sprintf(buf, "bus %d ", dev->secondary);
}
printk_debug(
"PCI: %02x:%02x.%01x %02x <- [0x%08lx - 0x%08lx] %s%s\n",
dev->bus->secondary,
PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
resource->index,
resource->base, limit,
buf,
(resource->flags & IORESOURCE_IO)? "io":
(resource->flags & IORESOURCE_PREFETCH)? "prefmem": "mem");
return;
}
static void pci_dev_set_resources(struct device *dev)
{
struct resource *resource, *last;
uint8_t line;
last = &dev->resource[dev->resources];
for(resource = &dev->resource[0]; resource < last; resource++) {
pci_set_resource(dev, resource);
}
if (dev->children) {
assign_resources(dev);
}
/* set a default latency timer */
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
/* set a default secondary latency timer */
if ((dev->hdr_type & 0x7f) == PCI_HEADER_TYPE_BRIDGE) {
pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 0x40);
}
/* zero the irq settings */
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &line);
if (line) {
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 0);
}
/* set the cache line size, so far 64 bytes is good for everyone */
pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 64 >> 2);
}
struct device_operations default_pci_ops_dev = {
.read_resources = pci_dev_read_resources,
.set_resources = pci_dev_set_resources,
.init = 0,
.scan_bus = 0,
};
struct device_operations default_pci_ops_bus = {
.read_resources = pci_bus_read_resources,
.set_resources = pci_dev_set_resources,
.init = 0,
.scan_bus = pci_scan_bridge,
};
static void set_pci_ops(struct device *dev)
{
struct pci_driver *driver;
if (dev->ops) {
return;
}
/* Look through the list of setup drivers and find one for
* this pci device
*/
for(driver = &pci_drivers[0]; driver != &epci_drivers[0]; driver++) {
if ((driver->vendor == dev->vendor) &&
(driver->device = dev->device)) {
dev->ops = driver->ops;
break;
}
}
/* If I don't have a specific driver use the default operations */
switch(dev->hdr_type & 0x7f) { /* header type */
case PCI_HEADER_TYPE_NORMAL: /* standard header */
if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)
goto bad;
dev->ops = &default_pci_ops_dev;
break;
case PCI_HEADER_TYPE_BRIDGE:
if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
goto bad;
dev->ops = &default_pci_ops_bus;
break;
default:
bad:
printk_err("PCI: %02x:%02x.%01x [%04x/%04x/%06x] has unknown header "
"type %02x, ignoring.\n",
dev->bus->secondary,
PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
dev->vendor, dev->device,
dev->class >> 8, dev->hdr_type);
}
return;
}
/**
* Given a bus and a devfn number, find the device structure
* @param bus The bus structure
* @param devfn a device/function number
* @return pointer to the device structure
*/
static struct device *pci_scan_get_dev(struct device **list, unsigned int devfn)
{
struct device *dev = 0;
for(; *list; list = &(*list)->sibling) {
if ((*list)->devfn == devfn) {
/* Unlink from the list */
dev = *list;
*list = (*list)->sibling;
dev->sibling = 0;
break;
}
}
return dev;
}
/** Scan the pci bus devices and bridges.
* @param pci_bus pointer to the bus structure
* @param max current bus number
* @return The maximum bus number found, after scanning all subordinate busses
*/
unsigned int pci_scan_bus(struct device *bus, unsigned int max)
{
unsigned int devfn;
struct device *dev, **bus_last;
struct device *old_devices;
struct device *child;
printk_debug("PCI: pci_scan_bus for bus %d\n", bus->secondary);
old_devices = bus->children;
bus->children = 0;
bus_last = &bus->children;
post_code(0x24);
/* probe all devices on this bus with some optimization for non-existance and
single funcion devices */
for (devfn = 0; devfn < 0xff; devfn++) {
struct device dummy;
uint32_t id, class;
uint8_t cmd, tmp, hdr_type;
/* First thing setup the device structure */
dev = pci_scan_get_dev(&old_devices, devfn);
dummy.bus = bus;
dummy.devfn = devfn;
pci_read_config_dword(&dummy, PCI_VENDOR_ID, &id);
/* some broken boards return 0 if a slot is empty: */
if (!dev &&
(id == 0xffffffff || id == 0x00000000 ||
id == 0x0000ffff || id == 0xffff0000)) {
printk_spew("PCI: devfn 0x%x, bad id 0x%x\n", devfn, id);
if (PCI_FUNC(devfn) == 0x00) {
/* if this is a function 0 device and it is not present,
skip to next device */
devfn += 0x07;
}
/* multi function device, skip to next function */
continue;
}
pci_read_config_byte(&dummy, PCI_HEADER_TYPE, &hdr_type);
pci_read_config_dword(&dummy, PCI_CLASS_REVISION, &class);
if (!dev) {
if ((dev = malloc(sizeof(*dev))) == 0) {
printk_err("PCI: out of memory.\n");
continue;
}
memset(dev, 0, sizeof(*dev));
}
dev->bus = bus;
dev->devfn = devfn;
dev->vendor = id & 0xffff;
dev->device = (id >> 16) & 0xffff;
dev->hdr_type = hdr_type;
/* class code, the upper 3 bytes of PCI_CLASS_REVISION */
dev->class = class >> 8;
/* non-destructively determine if device can be a master: */
pci_read_config_byte(dev, PCI_COMMAND, &cmd);
pci_write_config_byte(dev, PCI_COMMAND, cmd | PCI_COMMAND_MASTER);
pci_read_config_byte(dev, PCI_COMMAND, &tmp);
dev->master = ((tmp & PCI_COMMAND_MASTER) != 0);
pci_write_config_byte(dev, PCI_COMMAND, cmd);
/* Look at the vendor and device id, or at least the
* header type and class and figure out which set of configuration
* methods to use.
*/
set_pci_ops(dev);
/* Kill the device if we don't have some pci operations for it */
if (!dev->ops) {
free(dev);
continue;
}
printk_debug("PCI: %02x:%02x.%01x [%04x/%04x]\n",
bus->secondary, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
dev->vendor, dev->device);
/* Put it into the global device chain. */
append_device(dev);
/* Now insert it into the list of devices held by the parent bus. */
*bus_last = dev;
bus_last = &dev->sibling;
if (PCI_FUNC(devfn) == 0x00 && (hdr_type & 0x80) != 0x80) {
/* if this is not a multi function device, don't waste time probe
another function. Skip to next device. */
devfn += 0x07;
}
}
post_code(0x25);
for(child = bus->children; child; child = child->sibling) {
if (!child->ops->scan_bus)
continue;
max = child->ops->scan_bus(child, max);
}
/*
* We've scanned the bus and so we know all about what's on
* the other side of any bridges that may be on this bus plus
* any devices.
*
* Return how far we've got finding sub-buses.
*/
printk_debug("PCI: pci_scan_bus returning with max=%02x\n", max);
post_code(0x55);
return max;
}
/** Scan the bus, first for bridges and next for devices.
* @param pci_bus pointer to the bus structure
* @return The maximum bus number found, after scanning all subordinate busses
*/
static unsigned int pci_scan_bridge(struct device *bus, unsigned int max)
{
uint32_t buses;
uint16_t cr;
/* Set up the primary, secondary and subordinate bus numbers. We have
* no idea how many buses are behind this bridge yet, so we set the
* subordinate bus number to 0xff for the moment
*/
bus->secondary = ++max;
bus->subordinate = 0xff;
/* Clear all status bits and turn off memory, I/O and master enables. */
pci_read_config_word(bus, PCI_COMMAND, &cr);
pci_write_config_word(bus, PCI_COMMAND, 0x0000);
pci_write_config_word(bus, PCI_STATUS, 0xffff);
/*
* Read the existing primary/secondary/subordinate bus
* number configuration.
*/
pci_read_config_dword(bus, PCI_PRIMARY_BUS, &buses);
/* Configure the bus numbers for this bridge: the configuration
* transactions will not be propagated by the bridge if it is not
* correctly configured
*/
buses &= 0xff000000;
buses |= (((unsigned int) (bus->bus->secondary) << 0) |
((unsigned int) (bus->secondary) << 8) |
((unsigned int) (bus->subordinate) << 16));
pci_write_config_dword(bus, PCI_PRIMARY_BUS, buses);
/* Now we can scan all subordinate buses i.e. the bus hehind the bridge */
max = pci_scan_bus(bus, max);
/* We know the number of buses behind this bridge. Set the subordinate
* bus number to its real value
*/
bus->subordinate = max;
buses = (buses & 0xff00ffff) |
((unsigned int) (bus->subordinate) << 16);
pci_write_config_dword(bus, PCI_PRIMARY_BUS, buses);
pci_write_config_word(bus, PCI_COMMAND, cr);
return max;
}
static void pci_root_read_resources(struct device *bus)
{
int res = 0;
/* Initialize the system wide io space constraints */
bus->resource[res].base = 0x400;
bus->resource[res].size = 0;
bus->resource[res].align = 0;
bus->resource[res].gran = 0;
bus->resource[res].limit = 0xffffUL;
bus->resource[res].flags = IORESOURCE_IO;
bus->resource[res].index = PCI_IO_BASE;
compute_allocate_resource(bus, &bus->resource[res],
IORESOURCE_IO, IORESOURCE_IO);
res++;
/* Initialize the system wide memory resources constraints */
bus->resource[res].base = 0;
bus->resource[res].size = 0;
bus->resource[res].align = 0;
bus->resource[res].gran = 0;
bus->resource[res].limit = 0xffffffffUL;
bus->resource[res].flags = IORESOURCE_MEM;
bus->resource[res].index = PCI_MEMORY_BASE;
compute_allocate_resource(bus, &bus->resource[res],
IORESOURCE_MEM, IORESOURCE_MEM);
res++;
bus->resources = res;
}
static void pci_root_set_resources(struct device *bus)
{
compute_allocate_resource(bus,
&bus->resource[0], IORESOURCE_IO, IORESOURCE_IO);
compute_allocate_resource(bus,
&bus->resource[1], IORESOURCE_MEM, IORESOURCE_MEM);
assign_resources(bus);
}
struct device_operations default_pci_ops_root = {
.read_resources = pci_root_read_resources,
.set_resources = pci_root_set_resources,
.init = 0,
.scan_bus = pci_scan_bus,
};

401
src/include/boot/elf.h Normal file
View File

@ -0,0 +1,401 @@
#ifndef ELF_H
#define ELF_H
/* Standard ELF types. */
#include <stdint.h>
#include <stddef.h>
#include <arch/boot/boot.h>
/* Type for a 16-bit quantity. */
typedef uint16_t Elf32_Half;
typedef uint16_t Elf64_Half;
/* Types for signed and unsigned 32-bit quantities. */
typedef uint32_t Elf32_Word;
typedef int32_t Elf32_Sword;
typedef uint32_t Elf64_Word;
typedef int32_t Elf64_Sword;
/* Types for signed and unsigned 64-bit quantities. */
typedef uint64_t Elf32_Xword;
typedef int64_t Elf32_Sxword;
typedef uint64_t Elf64_Xword;
typedef int64_t Elf64_Sxword;
/* Type of addresses. */
typedef uint32_t Elf32_Addr;
typedef uint64_t Elf64_Addr;
/* Type of file offsets. */
typedef uint32_t Elf32_Off;
typedef uint64_t Elf64_Off;
/* Type for section indices, which are 16-bit quantities. */
typedef uint16_t Elf32_Section;
typedef uint16_t Elf64_Section;
/* Type of symbol indices. */
typedef uint32_t Elf32_Symndx;
typedef uint64_t Elf64_Symndx;
/* The ELF file header. This appears at the start of every ELF file. */
#define EI_NIDENT (16)
typedef struct
{
unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
Elf32_Half e_type; /* Object file type */
Elf32_Half e_machine; /* Architecture */
Elf32_Word e_version; /* Object file version */
Elf32_Addr e_entry; /* Entry point virtual address */
Elf32_Off e_phoff; /* Program header table file offset */
Elf32_Off e_shoff; /* Section header table file offset */
Elf32_Word e_flags; /* Processor-specific flags */
Elf32_Half e_ehsize; /* ELF header size in bytes */
Elf32_Half e_phentsize; /* Program header table entry size */
Elf32_Half e_phnum; /* Program header table entry count */
Elf32_Half e_shentsize; /* Section header table entry size */
Elf32_Half e_shnum; /* Section header table entry count */
Elf32_Half e_shstrndx; /* Section header string table index */
} Elf32_Ehdr;
typedef struct
{
unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
Elf64_Half e_type; /* Object file type */
Elf64_Half e_machine; /* Architecture */
Elf64_Word e_version; /* Object file version */
Elf64_Addr e_entry; /* Entry point virtual address */
Elf64_Off e_phoff; /* Program header table file offset */
Elf64_Off e_shoff; /* Section header table file offset */
Elf64_Word e_flags; /* Processor-specific flags */
Elf64_Half e_ehsize; /* ELF header size in bytes */
Elf64_Half e_phentsize; /* Program header table entry size */
Elf64_Half e_phnum; /* Program header table entry count */
Elf64_Half e_shentsize; /* Section header table entry size */
Elf64_Half e_shnum; /* Section header table entry count */
Elf64_Half e_shstrndx; /* Section header string table index */
} Elf64_Ehdr;
/* Fields in the e_ident array. The EI_* macros are indices into the
array. The macros under each EI_* macro are the values the byte
may have. */
#define EI_MAG0 0 /* File identification byte 0 index */
#define ELFMAG0 0x7f /* Magic number byte 0 */
#define EI_MAG1 1 /* File identification byte 1 index */
#define ELFMAG1 'E' /* Magic number byte 1 */
#define EI_MAG2 2 /* File identification byte 2 index */
#define ELFMAG2 'L' /* Magic number byte 2 */
#define EI_MAG3 3 /* File identification byte 3 index */
#define ELFMAG3 'F' /* Magic number byte 3 */
/* Conglomeration of the identification bytes, for easy testing as a word. */
#define ELFMAG "\177ELF"
#define SELFMAG 4
#define EI_CLASS 4 /* File class byte index */
#define ELFCLASSNONE 0 /* Invalid class */
#define ELFCLASS32 1 /* 32-bit objects */
#define ELFCLASS64 2 /* 64-bit objects */
#define ELFCLASSNUM 3
#define EI_DATA 5 /* Data encoding byte index */
#define ELFDATANONE 0 /* Invalid data encoding */
#define ELFDATA2LSB 1 /* 2's complement, little endian */
#define ELFDATA2MSB 2 /* 2's complement, big endian */
#define ELFDATANUM 3
#define EI_VERSION 6 /* File version byte index */
/* Value must be EV_CURRENT */
#define EI_OSABI 7 /* OS ABI identification */
#define ELFOSABI_SYSV 0 /* UNIX System V ABI */
#define ELFOSABI_HPUX 1 /* HP-UX */
#define ELFOSABI_ARM 97 /* ARM */
#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */
#define EI_ABIVERSION 8 /* ABI version */
#define EI_PAD 9 /* Byte index of padding bytes */
/* Legal values for e_type (object file type). */
#define ET_NONE 0 /* No file type */
#define ET_REL 1 /* Relocatable file */
#define ET_EXEC 2 /* Executable file */
#define ET_DYN 3 /* Shared object file */
#define ET_CORE 4 /* Core file */
#define ET_NUM 5 /* Number of defined types */
#define ET_LOPROC 0xff00 /* Processor-specific */
#define ET_HIPROC 0xffff /* Processor-specific */
/* Legal values for e_machine (architecture). */
#define EM_NONE 0 /* No machine */
#define EM_M32 1 /* AT&T WE 32100 */
#define EM_SPARC 2 /* SUN SPARC */
#define EM_386 3 /* Intel 80386 */
#define EM_68K 4 /* Motorola m68k family */
#define EM_88K 5 /* Motorola m88k family */
#define EM_486 6 /* Intel 80486 */
#define EM_860 7 /* Intel 80860 */
#define EM_MIPS 8 /* MIPS R3000 big-endian */
#define EM_S370 9 /* Amdahl */
#define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */
#define EM_RS6000 11 /* RS6000 */
#define EM_PARISC 15 /* HPPA */
#define EM_nCUBE 16 /* nCUBE */
#define EM_VPP500 17 /* Fujitsu VPP500 */
#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */
#define EM_960 19 /* Intel 80960 */
#define EM_PPC 20 /* PowerPC */
#define EM_V800 36 /* NEC V800 series */
#define EM_FR20 37 /* Fujitsu FR20 */
#define EM_RH32 38 /* TRW RH32 */
#define EM_MMA 39 /* Fujitsu MMA */
#define EM_ARM 40 /* ARM */
#define EM_FAKE_ALPHA 41 /* Digital Alpha */
#define EM_SH 42 /* Hitachi SH */
#define EM_SPARCV9 43 /* SPARC v9 64-bit */
#define EM_TRICORE 44 /* Siemens Tricore */
#define EM_ARC 45 /* Argonaut RISC Core */
#define EM_H8_300 46 /* Hitachi H8/300 */
#define EM_H8_300H 47 /* Hitachi H8/300H */
#define EM_H8S 48 /* Hitachi H8S */
#define EM_H8_500 49 /* Hitachi H8/500 */
#define EM_IA_64 50 /* Intel Merced */
#define EM_MIPS_X 51 /* Stanford MIPS-X */
#define EM_COLDFIRE 52 /* Motorola Coldfire */
#define EM_68HC12 53 /* Motorola M68HC12 */
#define EM_NUM 54
/* If it is necessary to assign new unofficial EM_* values, please
pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the
chances of collision with official or non-GNU unofficial values. */
#define EM_ALPHA 0x9026
/* Legal values for e_version (version). */
#define EV_NONE 0 /* Invalid ELF version */
#define EV_CURRENT 1 /* Current version */
#define EV_NUM 2
/* Program segment header. */
typedef struct
{
Elf32_Word p_type; /* Segment type */
Elf32_Off p_offset; /* Segment file offset */
Elf32_Addr p_vaddr; /* Segment virtual address */
Elf32_Addr p_paddr; /* Segment physical address */
Elf32_Word p_filesz; /* Segment size in file */
Elf32_Word p_memsz; /* Segment size in memory */
Elf32_Word p_flags; /* Segment flags */
Elf32_Word p_align; /* Segment alignment */
} Elf32_Phdr;
typedef struct
{
Elf64_Word p_type; /* Segment type */
Elf64_Word p_flags; /* Segment flags */
Elf64_Off p_offset; /* Segment file offset */
Elf64_Addr p_vaddr; /* Segment virtual address */
Elf64_Addr p_paddr; /* Segment physical address */
Elf64_Xword p_filesz; /* Segment size in file */
Elf64_Xword p_memsz; /* Segment size in memory */
Elf64_Xword p_align; /* Segment alignment */
} Elf64_Phdr;
/* Legal values for p_type (segment type). */
#define PT_NULL 0 /* Program header table entry unused */
#define PT_LOAD 1 /* Loadable program segment */
#define PT_DYNAMIC 2 /* Dynamic linking information */
#define PT_INTERP 3 /* Program interpreter */
#define PT_NOTE 4 /* Auxiliary information */
#define PT_SHLIB 5 /* Reserved */
#define PT_PHDR 6 /* Entry for header table itself */
#define PT_NUM 7 /* Number of defined types. */
#define PT_LOOS 0x60000000 /* Start of OS-specific */
#define PT_HIOS 0x6fffffff /* End of OS-specific */
#define PT_LOPROC 0x70000000 /* Start of processor-specific */
#define PT_HIPROC 0x7fffffff /* End of processor-specific */
/* Legal values for p_flags (segment flags). */
#define PF_X (1 << 0) /* Segment is executable */
#define PF_W (1 << 1) /* Segment is writable */
#define PF_R (1 << 2) /* Segment is readable */
#define PF_MASKPROC 0xf0000000 /* Processor-specific */
/* Note section contents. Each entry in the note section begins with
a header of a fixed form. */
typedef struct
{
Elf32_Word n_namesz; /* Length of the note's name. */
Elf32_Word n_descsz; /* Length of the note's descriptor. */
Elf32_Word n_type; /* Type of the note. */
} Elf32_Nhdr;
typedef struct
{
Elf64_Word n_namesz; /* Length of the note's name. */
Elf64_Word n_descsz; /* Length of the note's descriptor. */
Elf64_Word n_type; /* Type of the note. */
} Elf64_Nhdr;
/* Known names of notes. */
/* Solaris entries in the note section have this name. */
#define ELF_NOTE_SOLARIS "SUNW Solaris"
/* Note entries for GNU systems have this name. */
#define ELF_NOTE_GNU "GNU"
/* Defined types of notes for Solaris. */
/* Value of descriptor (one word) is desired pagesize for the binary. */
#define ELF_NOTE_PAGESIZE_HINT 1
/* Defined note types for GNU systems. */
/* ABI information. The descriptor consists of words:
word 0: OS descriptor
word 1: major version of the ABI
word 2: minor version of the ABI
word 3: subminor version of the ABI
*/
#define ELF_NOTE_ABI 1
/* Known OSes. These value can appear in word 0 of an ELF_NOTE_ABI
note section entry. */
#define ELF_NOTE_OS_LINUX 0
#define ELF_NOTE_OS_GNU 1
#define ELF_NOTE_OS_SOLARIS2 2
/* Motorola 68k specific definitions. */
/* Intel 80386 specific definitions. */
/* SUN SPARC specific definitions. */
/* Values for Elf64_Ehdr.e_flags. */
#define EF_SPARCV9_MM 3
#define EF_SPARCV9_TSO 0
#define EF_SPARCV9_PSO 1
#define EF_SPARCV9_RMO 2
#define EF_SPARC_EXT_MASK 0xFFFF00
#define EF_SPARC_SUN_US1 0x000200
#define EF_SPARC_HAL_R1 0x000400
/* MIPS R3000 specific definitions. */
/* Legal values for e_flags field of Elf32_Ehdr. */
#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used */
#define EF_MIPS_PIC 2 /* Contains PIC code */
#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence */
#define EF_MIPS_XGOT 8
#define EF_MIPS_64BIT_WHIRL 16
#define EF_MIPS_ABI2 32
#define EF_MIPS_ABI_ON32 64
#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level */
/* Legal values for MIPS architecture level. */
#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */
#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */
#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */
#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */
#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */
/* Legal values for p_type field of Elf32_Phdr. */
#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */
#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */
#define PT_MIPS_OPTIONS 0x70000002
/* Special program header types. */
#define PF_MIPS_LOCAL 0x10000000
/* HPPA specific definitions. */
/* Legal values for e_flags field of Elf32_Ehdr. */
#define EF_PARISC_TRAPNL 1 /* Trap nil pointer dereference. */
#define EF_PARISC_EXT 2 /* Program uses arch. extensions. */
#define EF_PARISC_ARCH 0xffff0000 /* Architecture version. */
/* Defined values are:
0x020b PA-RISC 1.0 big-endian
0x0210 PA-RISC 1.1 big-endian
0x028b PA-RISC 1.0 little-endian
0x0290 PA-RISC 1.1 little-endian
*/
/* Alpha specific definitions. */
/* Legal values for e_flags field of Elf64_Ehdr. */
#define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */
#define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */
/* PowerPC specific declarations */
/* ARM specific declarations */
/* Processor specific flags for the ELF header e_flags field. */
#define EF_ARM_RELEXEC 0x01
#define EF_ARM_HASENTRY 0x02
#define EF_ARM_INTERWORK 0x04
#define EF_ARM_APCS_26 0x08
#define EF_ARM_APCS_FLOAT 0x10
#define EF_ARM_PIC 0x20
#define EF_ALIGN8 0x40 /* 8-bit structure alignment is in use */
#define EF_NEW_ABI 0x80
#define EF_OLD_ABI 0x100
/* ARM-specific program header flags */
#define PF_ARM_SB 0x10000000 /* Segment contains the location
addressed by the static base */
#if ELF_CLASS == ELFCLASS32
typedef Elf32_Ehdr Elf_ehdr;
typedef Elf32_Phdr Elf_phdr;
#endif
#if ELF_CLASS == ELFCLASS64
typedef Elf64_Ehdr Elf_ehdr;
typedef Elf64_Phdr Elf_phdr;
#endif
extern int elf_check_arch(Elf_ehdr *ehdr);
extern void jmp_to_elf_entry(void *entry, unsigned long buffer);
struct lb_memory;
extern int elfboot(struct lb_memory *mem);
#define FIRMWARE_TYPE "LinuxBIOS"
#define BOOTLOADER "elfboot"
#define BOOTLOADER_VERSION "1.3"
#endif /* elf.h */

View File

@ -0,0 +1,89 @@
#ifndef ELF_BOOT_H
#define ELF_BOOT_H
#include <stdint.h>
/* This defines the structure of a table of parameters useful for ELF
* bootable images. These parameters are all passed and generated
* by the bootloader to the booted image. For simplicity and
* consistency the Elf Note format is reused.
*
* All of the information must be Position Independent Data.
* That is it must be safe to relocate the whole ELF boot parameter
* block without changing the meaning or correctnes of the data.
* Additionally it must be safe to permute the order of the ELF notes
* to any possible permutation without changing the meaning or correctness
* of the data.
*
*/
#define ELF_HEAD_SIZE (8*1024)
#define ELF_BOOT_MAGIC 0x0E1FB007
typedef uint16_t Elf_Half;
typedef uint32_t Elf_Word;
typedef uint64_t Elf_Xword;
typedef struct
{
Elf_Word b_signature; /* "0x0E1FB007" */
Elf_Word b_size;
Elf_Half b_checksum;
Elf_Half b_records;
} Elf_Bhdr;
typedef struct
{
Elf_Word n_namesz; /* Length of the note's name. */
Elf_Word n_descsz; /* Length of the note's descriptor. */
Elf_Word n_type; /* Type of the note. */
} Elf_Nhdr;
/* For standard notes n_namesz must be zero */
/* All of the following standard note types provide a single null
* terminated string in the descriptor.
*/
#define EBN_FIRMWARE_TYPE 0x00000001
/* On platforms that support multiple classes of firmware this field
* specifies the class of firmware you are loaded under.
*/
#define EBN_BOOTLOADER_NAME 0x00000002
/* This specifies just the name of the bootloader for easy comparison */
#define EBN_BOOTLOADER_VERSION 0x00000003
/* This specifies the version of the bootlader */
#define EBN_COMMAND_LINE 0x00000004
/* This specifies a command line that can be set by user interaction,
* and is provided as a free form string to the loaded image.
*/
/* Standardized Elf image notes for booting... The name for all of these is ELFBoot */
#define ELF_NOTE_BOOT "ELFBoot"
#define EIN_PROGRAM_NAME 0x00000001
/* The program in this ELF file */
#define EIN_PROGRAM_VERSION 0x00000002
/* The version of the program in this ELF file */
#define EIN_PROGRAM_CHECKSUM 0x00000003
/* ip style checksum of the memory image. */
/* Linux image notes for booting... The name for all of these is Linux */
#define LINUX_NOTE_BOOT "Linux"
#define LIN_COMMAND_LINE 0x00000001
/* The command line to pass to the loaded kernel. */
#define LIN_ROOT_DEV 0x00000002
/* The root dev to pass to the loaded kernel. */
#define LIN_RAMDISK_FLAGS 0x00000003
/* Various old ramdisk flags */
#define LIN_INITRD_START 0x00000004
/* Start of the ramdisk in bytes */
#define LIN_INITRD_SIZE 0x00000005
/* Size of the ramdisk in bytes */
#endif /* ELF_BOOT_H */

View File

@ -0,0 +1,183 @@
#ifndef LINUXBIOS_TABLES_H
#define LINUXBIOS_TABLES_H
#include <stdint.h>
/* The linuxbios table information is for conveying information
* from the firmware to the loaded OS image. Primarily this
* is expected to be information that cannot be discovered by
* other means, such as quering the hardware directly.
*
* All of the information should be Position Independent Data.
* That is it should be safe to relocated any of the information
* without it's meaning/correctnes changing. For table that
* can reasonably be used on multiple architectures the data
* size should be fixed. This should ease the transition between
* 32 bit and 64 bit architectures etc.
*
* The completeness test for the information in this table is:
* - Can all of the hardware be detected?
* - Are the per motherboard constants available?
* - Is there enough to allow a kernel to run that was written before
* a particular motherboard is constructed? (Assuming the kernel
* has drivers for all of the hardware but it does not have
* assumptions on how the hardware is connected together).
*
* With this test it should be straight forward to determine if a
* table entry is required or not. This should remove much of the
* long term compatibility burden as table entries which are
* irrelevant or have been replaced by better alternatives may be
* dropped. Of course it is polite and expidite to include extra
* table entries and be backwards compatible, but it is not required.
*/
struct lb_header
{
uint8_t signature[4]; /* LBIO */
uint32_t header_bytes;
uint32_t header_checksum;
uint32_t table_bytes;
uint32_t table_checksum;
uint32_t table_entries;
};
/* Every entry in the boot enviroment list will correspond to a boot
* info record. Encoding both type and size. The type is obviously
* so you can tell what it is. The size allows you to skip that
* boot enviroment record if you don't know what it easy. This allows
* forward compatibility with records not yet defined.
*/
struct lb_record {
uint32_t tag; /* tag ID */
uint32_t size; /* size of record (in bytes) */
};
#define LB_TAG_UNUSED 0x0000
#define LB_TAG_MEMORY 0x0001
struct lb_memory_range {
uint64_t start;
uint64_t size;
uint32_t type;
#define LB_MEM_RAM 1 /* Memory anyone can use */
#define LB_MEM_RESERVED 2 /* Don't use this memory region */
#define LB_MEM_TABLE 16 /* Ram configuration tables are kept in */
};
struct lb_memory {
uint32_t tag;
uint32_t size;
struct lb_memory_range map[0];
};
#define LB_TAG_HWRPB 0x0002
struct lb_hwrpb {
uint32_t tag;
uint32_t size;
uint64_t hwrpb;
};
#define LB_TAG_MAINBOARD 0x0003
struct lb_mainboard {
uint32_t tag;
uint32_t size;
uint8_t vendor_idx;
uint8_t part_number_idx;
uint8_t strings[0];
};
#define LB_TAG_VERSION 0x0004
#define LB_TAG_EXTRA_VERSION 0x0005
#define LB_TAG_BUILD 0x0006
#define LB_TAG_COMPILE_TIME 0x0007
#define LB_TAG_COMPILE_BY 0x0008
#define LB_TAG_COMPILE_HOST 0x0009
#define LB_TAG_COMPILE_DOMAIN 0x000a
#define LB_TAG_COMPILER 0x000b
#define LB_TAG_LINKER 0x000c
#define LB_TAG_ASSEMBLER 0x000d
struct lb_string {
uint32_t tag;
uint32_t size;
uint8_t string[0];
};
/* The following structures are for the cmos definitions table */
#define LB_TAG_CMOS_OPTION_TABLE 200
/* cmos header record */
struct cmos_option_table {
uint32_t tag; /* CMOS definitions table type */
uint32_t size; /* size of the entire table */
uint32_t header_length; /* length of header */
};
/* cmos entry record
This record is variable length. The name field may be
shorter than CMOS_MAX_NAME_LENGTH. The entry may start
anywhere in the byte, but can not span bytes unless it
starts at the beginning of the byte and the length is
fills complete bytes.
*/
#define LB_TAG_OPTION 201
struct cmos_entries {
uint32_t tag; /* entry type */
uint32_t size; /* length of this record */
uint32_t bit; /* starting bit from start of image */
uint32_t length; /* length of field in bits */
uint32_t config; /* e=enumeration, h=hex, r=reserved */
uint32_t config_id; /* a number linking to an enumeration record */
#define CMOS_MAX_NAME_LENGTH 32
uint8_t name[CMOS_MAX_NAME_LENGTH]; /* name of entry in ascii,
variable length int aligned */
};
/* cmos enumerations record
This record is variable length. The text field may be
shorter than CMOS_MAX_TEXT_LENGTH.
*/
#define LB_TAG_OPTION_ENUM 202
struct cmos_enums {
uint32_t tag; /* enumeration type */
uint32_t size; /* length of this record */
uint32_t config_id; /* a number identifying the config id */
uint32_t value; /* the value associated with the text */
#define CMOS_MAX_TEXT_LENGTH 32
uint8_t text[CMOS_MAX_TEXT_LENGTH]; /* enum description in ascii,
variable length int aligned */
};
/* cmos defaults record
This record contains default settings for the cmos ram.
*/
#define LB_TAG_OPTION_DEFAULTS 203
struct cmos_defaults {
uint32_t tag; /* default type */
uint32_t size; /* length of this record */
uint32_t name_length; /* length of the following name field */
uint8_t name[CMOS_MAX_NAME_LENGTH]; /* name identifying the default */
#define CMOS_IMAGE_BUFFER_SIZE 128
uint8_t default_set[CMOS_IMAGE_BUFFER_SIZE]; /* default settings */
};
#define LB_TAG_OPTION_CHECKSUM 204
struct cmos_checksum {
uint32_t tag;
uint32_t size;
/* In practice everything is byte aligned, but things are measured
* in bits to be consistent.
*/
uint32_t range_start; /* First bit that is checksummed (byte aligned) */
uint32_t range_end; /* Last bit that is checksummed (byte aligned) */
uint32_t location; /* First bit of the checksum (byte aligned) */
uint32_t type; /* Checksum algorithm that is used */
#define CHECKSUM_NONE 0
#define CHECKSUM_PCBIOS 1
};
#endif /* LINUXBIOS_TABLES_H */

View File

@ -0,0 +1,9 @@
#ifndef BOOT_TABLES_H
#define BOOT_TABLES_H
#include <mem.h>
#include <boot/linuxbios_tables.h>
struct lb_memory *write_tables(struct mem_range *mem, unsigned long *processor_map);
#endif /* BOOT_TABLES_H */

View File

@ -0,0 +1,76 @@
#ifndef CONSOLE_CONSOLE_H_
#define CONSOLE_CONSOLE_H_
#include <stdint.h>
#include <console/loglevel.h>
void console_init(void);
void console_tx_byte(unsigned char byte);
void console_tx_flush(void);
void post_code(uint8_t value);
void die(char *msg);
struct console_driver {
void (*init)(void);
void (*tx_byte)(unsigned char byte);
void (*tx_flush)(void);
};
#define __console __attribute__((unused, __section__ (".rodata.console_drivers")))
/* Defined by the linker... */
extern struct console_driver console_drivers[];
extern struct console_driver econsole_drivers[];
extern int console_loglevel;
int do_printk(int msg_level, const char *fmt, ...);
#define printk_emerg(fmt, arg...) do_printk(BIOS_EMERG ,fmt, ##arg)
#define printk_alert(fmt, arg...) do_printk(BIOS_ALERT ,fmt, ##arg)
#define printk_crit(fmt, arg...) do_printk(BIOS_CRIT ,fmt, ##arg)
#define printk_err(fmt, arg...) do_printk(BIOS_ERR ,fmt, ##arg)
#define printk_warning(fmt, arg...) do_printk(BIOS_WARNING ,fmt, ##arg)
#define printk_notice(fmt, arg...) do_printk(BIOS_NOTICE ,fmt, ##arg)
#define printk_info(fmt, arg...) do_printk(BIOS_INFO ,fmt, ##arg)
#define printk_debug(fmt, arg...) do_printk(BIOS_DEBUG ,fmt, ##arg)
#define printk_spew(fmt, arg...) do_printk(BIOS_SPEW ,fmt, ##arg)
#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_EMERG
#undef printk_emerg
#define printk_emerg(fmt, arg...) do {} while(0)
#endif
#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_ALERT
#undef printk_alert
#define printk_alart(fmt, arg...) do {} while(0)
#endif
#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_CRIT
#undef printk_crit
#define printk_crit(fmt, arg...) do {} while(0)
#endif
#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_ERR
#undef printk_err
#define printk_err(fmt, arg...) do {} while(0)
#endif
#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_WARNING
#undef printk_warning
#define printk_warning(fmt, arg...) do {} while(0)
#endif
#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_NOTICE
#undef printk_notice
#define printk_notice(fmt, arg...) do {} while(0)
#endif
#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_INFO
#undef printk_info
#define printk_info(fmt, arg...) do {} while(0)
#endif
#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_DEBUG
#undef printk_debug
#define printk_debug(fmt, arg...) do {} while(0)
#endif
#if MAXIMUM_CONSOLE_LOGLEVEL <= BIOS_SPEW
#undef printk_spew
#define printk_spew(fmt, arg...) do {} while(0)
#endif
#endif /* CONSOLE_CONSOLE_H_ */

View File

@ -0,0 +1,30 @@
#ifndef LOGLEVEL_H
#define LOGLEVEL_H
/* Safe for inclusion in assembly */
#ifndef MAXIMUM_CONSOLE_LOGLEVEL
#define MAXIMUM_CONSOLE_LOGLEVEL 8
#endif
#ifndef DEFAULT_CONSOLE_LOGLEVEL
#define DEFAULT_CONSOLE_LOGLEVEL 8 /* anything MORE serious than BIOS_SPEW */
#endif
#if (DEFAULT_CONSOLE_LOGLEVEL <= MAXIMUM_CONSOLE_LOGLEVEL)
#define ASM_CONSOLE_LOGLEVEL DEFAULT_CONSOLE_LOGLEVEL
#else
#define ASM_CONSOLE_LOGLEVEL MAXIMUM_CONSOLE_LOGLEVEL
#endif
#define BIOS_EMERG 0 /* system is unusable */
#define BIOS_ALERT 1 /* action must be taken immediately */
#define BIOS_CRIT 2 /* critical conditions */
#define BIOS_ERR 3 /* error conditions */
#define BIOS_WARNING 4 /* warning conditions */
#define BIOS_NOTICE 5 /* normal but significant condition */
#define BIOS_INFO 6 /* informational */
#define BIOS_DEBUG 7 /* debug-level messages */
#define BIOS_SPEW 8 /* Way too many details */
#endif /* LOGLEVEL_H */

11
src/include/cpu/cpu.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef CPU_CPU_H
#define CPU_CPU_H
#include <mem.h>
unsigned long cpu_initialize(struct mem_range *mem);
#define CPU_ENABLED 1 /* Processor is available */
#define CPU_BOOTPROCESSOR 2 /* Processor is the BP */
#endif /* CPU_CPU_H */

View File

@ -0,0 +1,24 @@
#ifndef CPU_CPUFIXUP_H
#define CPU_CPUFIXUP_H
struct mem_range;
#include <cpu/k8/cpufixup.h>
#include <cpu/k7/cpufixup.h>
#include <cpu/p6/cpufixup.h>
#if CPU_FIXUP == 1
# if defined(k8)
# define cpufixup(mem) k8_cpufixup(mem)
# elif defined(k7)
# define cpufixup(mem) k7_cpufixup(mem)
# elif defined(i786)
# define cpufixup(mem) i786_cpufixup(mem)
# elif defined(i686)
# define cpufixup(mem) p6_cpufixup(mem)
# endif
#else
# define cpufixup(mem) do {} while(0)
#endif
#endif /* CPU_CPUFIXUP_H */

View File

@ -0,0 +1,6 @@
#ifndef CPU_K7_CPUFIXUP_H
#define CPU_K7_CPUFIXUP_H
void k7_cpufixup(struct mem_range *mem);
#endif /* CPU_K7_CPUFIXUP_H */

42
src/include/cpu/k7/mtrr.h Normal file
View File

@ -0,0 +1,42 @@
#ifndef CPU_K7_MTRR_H
#define CPU_K7_MTRR_H
#include <cpu/p6/mtrr.h>
#define IORR_FIRST 0xC0010016
#define IORR_LAST 0xC0010019
#define SYSCFG 0xC0010010
#define MTRR_READ_MEM (1 << 4)
#define MTRR_WRITE_MEM (1 << 3)
#define SYSCFG_MSR 0xC0010010
#define SYSCFG_MSR_EvictEn (1 << 22)
#define SYSCFG_MSR_TOM2En (1 << 21)
#define SYSCFG_MSR_MtrrVarDramEn (1 << 20)
#define SYSCFG_MSR_MtrrFixDramModEn (1 << 19)
#define SYSCFG_MSR_MtrrFixDramEn (1 << 18)
#define SYSCFG_MSR_UcLockEn (1 << 17)
#define SYSCFG_MSR_ChxToDirtyDis (1 << 16)
#define SYSCFG_MSR_SysEccEn (1 << 15)
#define SYSCFG_MSR_RdBlkL2WayEn (1 << 14)
#define SYSCFG_MSR_SysFillValIsD1 (1 << 13)
#define SYSCFG_MSR_IcInclusive (1 << 12)
#define SYSCFG_MSR_ClVicBlkEn (1 << 11)
#define SYSCFG_MSR_SetDirtyEnO (1 << 10)
#define SYSCFG_MSR_SetDirtyEnS (1 << 9)
#define SYSCFG_MSR_SetDirtyEnE (1 << 8)
#define SYSCFG_MSR_SysVicLimitMask ((1 << 8) - (1 << 5))
#define SYSCFG_MSR_SysAckLimitMask ((1 << 5) - (1 << 0))
#define IORR0_BASE 0xC0010016
#define IORR0_MASK 0xC0010017
#define IORR1_BASE 0xC0010018
#define IORR1_MASK 0xC0010019
#define TOP_MEM 0xC001001A
#define TOP_MEM2 0xC001001D
#define HWCR_MSR 0xC0010015
#endif /* CPU_K7_MTRR_H */

View File

@ -0,0 +1,6 @@
#ifndef CPU_K8_CPUFIXUP_H
#define CPU_K8_CPUFIXUP_H
void k8_cpufixup(struct mem_range *mem);
#endif /* CPU_K8_CPUFIXUP_H */

45
src/include/cpu/k8/mtrr.h Normal file
View File

@ -0,0 +1,45 @@
#ifndef CPU_K8_MTRR_H
#define CPU_K8_MTRR_H
#include <cpu/k7/mtrr.h>
#if 0
#define IORR_FIRST 0xC0010016
#define IORR_LAST 0xC0010019
#define SYSCFG 0xC0010010
#define MTRR_READ_MEM (1 << 4)
#define MTRR_WRITE_MEM (1 << 3)
#define SYSCFG_MSR 0xC0010010
#define SYSCFG_MSR_EvictEn (1 << 22)
#define SYSCFG_MSR_TOM2En (1 << 21)
#define SYSCFG_MSR_MtrrVarDramEn (1 << 20)
#define SYSCFG_MSR_MtrrFixDramModEn (1 << 19)
#define SYSCFG_MSR_MtrrFixDramEn (1 << 18)
#define SYSCFG_MSR_UcLockEn (1 << 17)
#define SYSCFG_MSR_ChxToDirtyDis (1 << 16)
#define SYSCFG_MSR_SysEccEn (1 << 15)
#define SYSCFG_MSR_RdBlkL2WayEn (1 << 14)
#define SYSCFG_MSR_SysFillValIsD1 (1 << 13)
#define SYSCFG_MSR_IcInclusive (1 << 12)
#define SYSCFG_MSR_ClVicBlkEn (1 << 11)
#define SYSCFG_MSR_SetDirtyEnO (1 << 10)
#define SYSCFG_MSR_SetDirtyEnS (1 << 9)
#define SYSCFG_MSR_SetDirtyEnE (1 << 8)
#define SYSCFG_MSR_SysVicLimitMask ((1 << 8) - (1 << 5))
#define SYSCFG_MSR_SysAckLimitMask ((1 << 5) - (1 << 0))
#define IORR0_BASE 0xC0010016
#define IORR0_MASK 0xC0010017
#define IORR1_BASE 0xC0010018
#define IORR1_MASK 0xC0010019
#define TOP_MEM 0xC001001A
#define TOP_MEM2 0xC001001D
#define HWCR_MSR 0xC0010015
#endif
#endif /* CPU_K8_MTRR_H */

View File

@ -0,0 +1,25 @@
#ifndef CPU_P5_CPUID_H
#define CPU_P5_CPUID_H
int mtrr_check(void);
void display_cpuid(void);
/*
* Generic CPUID function. copied from Linux kernel headers
*/
static inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
{
__asm__("pushl %%ebx\n\t"
"cpuid\n\t"
"movl %%ebx, %%esi\n\t"
"popl %%ebx\n\t"
: "=a" (*eax),
"=S" (*ebx),
"=c" (*ecx),
"=d" (*edx)
: "a" (op)
: "cc");
}
#endif /* CPU_P5_CPUID_H */

175
src/include/cpu/p6/apic.h Normal file
View File

@ -0,0 +1,175 @@
#ifndef APIC_H
#define APIC_H
#define APIC_BASE_MSR 0x1B
#define APIC_BASE_MSR_BOOTSTRAP_PROCESSOR (1 << 8)
#define APIC_BASE_MSR_ENABLE (1 << 11)
#define APIC_BASE_MSR_ADDR_MASK 0xFFFFF000
#define APIC_DEFAULT_BASE 0xfee00000
#define APIC_ID 0x020
#define APIC_LVR 0x030
#define APIC_ARBID 0x090
#define APIC_RRR 0x0C0
#define APIC_SVR 0x0f0
#define APIC_SPIV 0x0f0
#define APIC_SPIV_ENABLE 0x100
#define APIC_ESR 0x280
#define APIC_ESR_SEND_CS 0x00001
#define APIC_ESR_RECV_CS 0x00002
#define APIC_ESR_SEND_ACC 0x00004
#define APIC_ESR_RECV_ACC 0x00008
#define APIC_ESR_SENDILL 0x00020
#define APIC_ESR_RECVILL 0x00040
#define APIC_ESR_ILLREGA 0x00080
#define APIC_ICR 0x300
#define APIC_DEST_SELF 0x40000
#define APIC_DEST_ALLINC 0x80000
#define APIC_DEST_ALLBUT 0xC0000
#define APIC_ICR_RR_MASK 0x30000
#define APIC_ICR_RR_INVALID 0x00000
#define APIC_ICR_RR_INPROG 0x10000
#define APIC_ICR_RR_VALID 0x20000
#define APIC_INT_LEVELTRIG 0x08000
#define APIC_INT_ASSERT 0x04000
#define APIC_ICR_BUSY 0x01000
#define APIC_DEST_LOGICAL 0x00800
#define APIC_DM_FIXED 0x00000
#define APIC_DM_LOWEST 0x00100
#define APIC_DM_SMI 0x00200
#define APIC_DM_REMRD 0x00300
#define APIC_DM_NMI 0x00400
#define APIC_DM_INIT 0x00500
#define APIC_DM_STARTUP 0x00600
#define APIC_DM_EXTINT 0x00700
#define APIC_VECTOR_MASK 0x000FF
#define APIC_ICR2 0x310
#define GET_APIC_DEST_FIELD(x) (((x)>>24)&0xFF)
#define SET_APIC_DEST_FIELD(x) ((x)<<24)
#define APIC_LVTT 0x320
#define APIC_LVTPC 0x340
#define APIC_LVT0 0x350
#define APIC_LVT_TIMER_BASE_MASK (0x3<<18)
#define GET_APIC_TIMER_BASE(x) (((x)>>18)&0x3)
#define SET_APIC_TIMER_BASE(x) (((x)<<18))
#define APIC_TIMER_BASE_CLKIN 0x0
#define APIC_TIMER_BASE_TMBASE 0x1
#define APIC_TIMER_BASE_DIV 0x2
#define APIC_LVT_TIMER_PERIODIC (1<<17)
#define APIC_LVT_MASKED (1<<16)
#define APIC_LVT_LEVEL_TRIGGER (1<<15)
#define APIC_LVT_REMOTE_IRR (1<<14)
#define APIC_INPUT_POLARITY (1<<13)
#define APIC_SEND_PENDING (1<<12)
#define APIC_LVT_RESERVED_1 (1<<11)
#define APIC_DELIVERY_MODE_MASK (7<<8)
#define APIC_DELIVERY_MODE_FIXED (0<<8)
#define APIC_DELIVERY_MODE_NMI (4<<8)
#define APIC_DELIVERY_MODE_EXTINT (7<<8)
#define GET_APIC_DELIVERY_MODE(x) (((x)>>8)&0x7)
#define SET_APIC_DELIVERY_MODE(x,y) (((x)&~0x700)|((y)<<8))
#define APIC_MODE_FIXED 0x0
#define APIC_MODE_NMI 0x4
#define APIC_MODE_EXINT 0x7
#define APIC_LVT1 0x360
#define APIC_LVTERR 0x370
#if !defined(ASSEMBLY)
#include <console/console.h>
#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
struct __xchg_dummy { unsigned long a[100]; };
#define __xg(x) ((struct __xchg_dummy *)(x))
/*
* Note: no "lock" prefix even on SMP: xchg always implies lock anyway
* Note 2: xchg has side effect, so that attribute volatile is necessary,
* but generally the primitive is invalid, *ptr is output argument. --ANK
*/
static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
{
switch (size) {
case 1:
__asm__ __volatile__("xchgb %b0,%1"
:"=q" (x)
:"m" (*__xg(ptr)), "0" (x)
:"memory");
break;
case 2:
__asm__ __volatile__("xchgw %w0,%1"
:"=r" (x)
:"m" (*__xg(ptr)), "0" (x)
:"memory");
break;
case 4:
__asm__ __volatile__("xchgl %0,%1"
:"=r" (x)
:"m" (*__xg(ptr)), "0" (x)
:"memory");
break;
}
return x;
}
static inline unsigned long apic_read(unsigned long reg)
{
return *((volatile unsigned long *)(APIC_DEFAULT_BASE+reg));
}
extern inline void apic_write_atomic(unsigned long reg, unsigned long v)
{
xchg((volatile unsigned long *)(APIC_DEFAULT_BASE+reg), v);
}
static inline void apic_write(unsigned long reg, unsigned long v)
{
*((volatile unsigned long *)(APIC_DEFAULT_BASE+reg)) = v;
}
static inline void apic_wait_icr_idle(void)
{
do { } while ( apic_read( APIC_ICR ) & APIC_ICR_BUSY );
}
#ifdef CONFIG_X86_GOOD_APIC
# define FORCE_READ_AROUND_WRITE 0
# define apic_read_around(x) apic_read(x)
# define apic_write_around(x,y) apic_write((x),(y))
#else
# define FORCE_READ_AROUND_WRITE 1
# define apic_read_around(x) apic_read(x)
# define apic_write_around(x,y) apic_write_atomic((x),(y))
#endif
static inline int apic_remote_read(int apicid, int reg, unsigned long *pvalue)
{
int timeout;
unsigned long status;
int result;
apic_wait_icr_idle();
apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
apic_write_around(APIC_ICR, APIC_DM_REMRD | (reg >> 4));
timeout = 0;
do {
#if 0
udelay(100);
#endif
status = apic_read(APIC_ICR) & APIC_ICR_RR_MASK;
} while (status == APIC_ICR_RR_INPROG && timeout++ < 1000);
result = -1;
if (status == APIC_ICR_RR_VALID) {
*pvalue = apic_read(APIC_RRR);
result = 0;
}
return result;
}
#endif /* ASSEMBLY */
#endif /* APIC_H */

View File

@ -0,0 +1,6 @@
#ifndef CPU_P6_CPUFIXUP_H
#define CPU_P6_CPUFIXUP_H
void p6_cpufixup(struct mem_range *mem);
#endif /* CPU_P6_CPUFIXUP_H */

33
src/include/cpu/p6/msr.h Normal file
View File

@ -0,0 +1,33 @@
#ifndef CPU_P6_MSR_H
#define CPU_P6_MSR_H
/*
* Access to machine-specific registers (available on 586 and better only)
* Note: the rd* operations modify the parameters directly (without using
* pointer indirection), this allows gcc to optimize better
*/
#define rdmsr(msr,val1,val2) \
__asm__ __volatile__("rdmsr" \
: "=a" (val1), "=d" (val2) \
: "c" (msr))
#define wrmsr(msr,val1,val2) \
__asm__ __volatile__("wrmsr" \
: /* no outputs */ \
: "c" (msr), "a" (val1), "d" (val2))
#define rdtsc(low,high) \
__asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
#define rdtscl(low) \
__asm__ __volatile__ ("rdtsc" : "=a" (low) : : "edx")
#define rdtscll(val) \
__asm__ __volatile__ ("rdtsc" : "=A" (val))
#define rdpmc(counter,low,high) \
__asm__ __volatile__("rdpmc" \
: "=a" (low), "=d" (high) \
: "c" (counter))
#endif /* CPU_P6_MSR_H */

44
src/include/cpu/p6/mtrr.h Normal file
View File

@ -0,0 +1,44 @@
#ifndef __LINUXBIOS_CPU_P6_MTRR_H
#define __LINUXBIOS_CPU_P6_MTRR_H
/* These are the region types */
#define MTRR_TYPE_UNCACHABLE 0
#define MTRR_TYPE_WRCOMB 1
/*#define MTRR_TYPE_ 2*/
/*#define MTRR_TYPE_ 3*/
#define MTRR_TYPE_WRTHROUGH 4
#define MTRR_TYPE_WRPROT 5
#define MTRR_TYPE_WRBACK 6
#define MTRR_NUM_TYPES 7
#define MTRRcap_MSR 0x0fe
#define MTRRdefType_MSR 0x2ff
#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
#define NUM_FIXED_RANGES 88
#define MTRRfix64K_00000_MSR 0x250
#define MTRRfix16K_80000_MSR 0x258
#define MTRRfix16K_A0000_MSR 0x259
#define MTRRfix4K_C0000_MSR 0x268
#define MTRRfix4K_C8000_MSR 0x269
#define MTRRfix4K_D0000_MSR 0x26a
#define MTRRfix4K_D8000_MSR 0x26b
#define MTRRfix4K_E0000_MSR 0x26c
#define MTRRfix4K_E8000_MSR 0x26d
#define MTRRfix4K_F0000_MSR 0x26e
#define MTRRfix4K_F8000_MSR 0x26f
#if !defined(ASSEMBLY)
void set_var_mtrr(unsigned int reg, unsigned long base, unsigned long size, unsigned char type);
#if defined(INTEL_PPRO_MTRR)
struct mem_range;
void setup_mtrrs(struct mem_range *mem);
#endif
#endif /* ASSEMBLY */
#endif /* __LINUXBIOS_CPU_P6_MTRR_H */

8
src/include/delay.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef DELAY_H
#define DELAY_H
void udelay(int usecs);
void mdelay(int msecs);
void delay(int secs);
#endif /* DELAY_H */

View File

@ -0,0 +1,7 @@
#ifndef IP_CHECKSUM_H
#define IP_CHECKSUM_H
unsigned long compute_ip_checksum(void *addr, unsigned long length);
unsigned long add_ip_checksums(unsigned long offset, unsigned long sum, unsigned long new);
#endif /* IP_CHECKSUM_H */

13
src/include/mem.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef MEM_H
#define MEM_H
struct mem_range {
unsigned long basek;
unsigned long sizek;
};
/* mem_range arrays are non-overlapping, in ascending order and null terminated */
struct mem_range *sizeram(void);
#endif /* MEM_H */

View File

@ -0,0 +1,16 @@
#ifndef PART_FALLBACK_BOOT_H
#define PART_FALLBACK_BOOT_H
#ifndef ASSEMBLY
#if HAVE_FALLBACK_BOOT
void boot_successful(void);
#else
#define boot_successful()
#endif
#endif /* ASSEMBLY */
#define RTC_BOOT_BYTE 48
#endif /* PART_FALLBACK_BOOT_H */

View File

@ -0,0 +1,7 @@
#ifndef PART_SIZERAM_H
#define PART_SIZERAM_H
struct mem_rang;
struct mem_range *sizeram(void);
#endif /* PART_SIZERAM_H */

View File

@ -0,0 +1,110 @@
#ifndef PC80_MC146818RTC_H
#define PC80_MC146818RTC_H
#ifndef RTC_BASE_PORT
#define RTC_BASE_PORT 0x70
#endif
#define RTC_PORT(x) (RTC_BASE_PORT + (x))
/* On PCs, the checksum is built only over bytes 16..45 */
#define PC_CKS_RANGE_START 16
#define PC_CKS_RANGE_END 45
#define PC_CKS_LOC 46
/* Linux bios checksum is built only over bytes 49..125 */
#define LB_CKS_RANGE_START 49
#define LB_CKS_RANGE_END 125
#define LB_CKS_LOC 126
/* control registers - Moto names
*/
#define RTC_REG_A 10
#define RTC_REG_B 11
#define RTC_REG_C 12
#define RTC_REG_D 13
/**********************************************************************
* register details
**********************************************************************/
#define RTC_FREQ_SELECT RTC_REG_A
/* update-in-progress - set to "1" 244 microsecs before RTC goes off the bus,
* reset after update (may take 1.984ms @ 32768Hz RefClock) is complete,
* totalling to a max high interval of 2.228 ms.
*/
# define RTC_UIP 0x80
# define RTC_DIV_CTL 0x70
/* divider control: refclock values 4.194 / 1.049 MHz / 32.768 kHz */
# define RTC_REF_CLCK_4MHZ 0x00
# define RTC_REF_CLCK_1MHZ 0x10
# define RTC_REF_CLCK_32KHZ 0x20
/* 2 values for divider stage reset, others for "testing purposes only" */
# define RTC_DIV_RESET1 0x60
# define RTC_DIV_RESET2 0x70
/* Periodic intr. / Square wave rate select. 0=none, 1=32.8kHz,... 15=2Hz */
# define RTC_RATE_SELECT 0x0F
# define RTC_RATE_NONE 0x00
# define RTC_RATE_32786HZ 0x01
# define RTC_RATE_16384HZ 0x02
# define RTC_RATE_8192HZ 0x03
# define RTC_RATE_4096HZ 0x04
# define RTC_RATE_2048HZ 0x05
# define RTC_RATE_1024HZ 0x06
# define RTC_RATE_512HZ 0x07
# define RTC_RATE_256HZ 0x08
# define RTC_RATE_128HZ 0x09
# define RTC_RATE_64HZ 0x0a
# define RTC_RATE_32HZ 0x0b
# define RTC_RATE_16HZ 0x0c
# define RTC_RATE_8HZ 0x0d
# define RTC_RATE_4HZ 0x0e
# define RTC_RATE_2HZ 0x0f
/**********************************************************************/
#define RTC_CONTROL RTC_REG_B
# define RTC_SET 0x80 /* disable updates for clock setting */
# define RTC_PIE 0x40 /* periodic interrupt enable */
# define RTC_AIE 0x20 /* alarm interrupt enable */
# define RTC_UIE 0x10 /* update-finished interrupt enable */
# define RTC_SQWE 0x08 /* enable square-wave output */
# define RTC_DM_BINARY 0x04 /* all time/date values are BCD if clear */
# define RTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */
# define RTC_DST_EN 0x01 /* auto switch DST - works f. USA only */
/**********************************************************************/
#define RTC_INTR_FLAGS RTC_REG_C
/* caution - cleared by read */
# define RTC_IRQF 0x80 /* any of the following 3 is active */
# define RTC_PF 0x40
# define RTC_AF 0x20
# define RTC_UF 0x10
/**********************************************************************/
#define RTC_VALID RTC_REG_D
# define RTC_VRT 0x80 /* valid RAM and time */
/**********************************************************************/
/* On PCs, the checksum is built only over bytes 16..45 */
#define PC_CKS_RANGE_START 16
#define PC_CKS_RANGE_END 45
#define PC_CKS_LOC 46
#define LB_CKS_RANGE_START 49
#define LB_CKS_RANGE_END 125
#define LB_CKS_LOC 126
#if !defined(ASSEMBLY)
void rtc_init(int invalid);
#if USE_OPTION_TABLE == 1
int get_option(void *dest, char *name);
#else
#define get_option(dest, name) (-2)
#endif
#endif
#endif /* PC80_MC146818RTC_H */

53
src/include/smp/atomic.h Normal file
View File

@ -0,0 +1,53 @@
#ifndef SMP_ATOMIC_H
#define SMP_ATOMIC_H
#ifdef SMP
#include <arch/smp/atomic.h>
#else
typedef struct { int counter; } atomic_t;
#define ATOMIC_INIT(i) { (i) }
/**
* atomic_read - read atomic variable
* @v: pointer of type atomic_t
*
* Atomically reads the value of @v. Note that the guaranteed
* useful range of an atomic_t is only 24 bits.
*/
#define atomic_read(v) ((v)->counter)
/**
* atomic_set - set atomic variable
* @v: pointer of type atomic_t
* @i: required value
*
* Atomically sets the value of @v to @i. Note that the guaranteed
* useful range of an atomic_t is only 24 bits.
*/
#define atomic_set(v,i) (((v)->counter) = (i))
/**
* atomic_inc - increment atomic variable
* @v: pointer of type atomic_t
*
* Atomically increments @v by 1. Note that the guaranteed
* useful range of an atomic_t is only 24 bits.
*/
#define atomic_inc(v) (((v)->counter)++)
/**
* atomic_dec - decrement atomic variable
* @v: pointer of type atomic_t
*
* Atomically decrements @v by 1. Note that the guaranteed
* useful range of an atomic_t is only 24 bits.
*/
#define atomic_dec(v) (((v)->counter)--)
#endif /* SMP */
#endif /* SMP_ATOMIC_H */

View File

@ -0,0 +1,24 @@
#ifndef SMP_SPINLOCK_H
#define SMP_SPINLOCK_H
#ifdef SMP
#include <arch/smp/spinlock.h>
#else /* !SMP */
/* Most GCC versions have a nasty bug with empty initializers */
#if (__GNUC__ > 2)
typedef struct { } spinlock_t;
#define SPIN_LOCK_UNLOCKED (spinlock_t) { }
#else
typedef struct { int gcc_is_buggy; } spinlock_t;
#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
#endif
#define barrier() do {} while(0)
#define spin_is_locked(lock) 0
#define spin_unlock_wait(lock) do {} while(0)
#define spin_lock(lock) do {} while(0)
#define spin_unlock(lock) do {} while(0)
#endif
#endif /* SMP_SPINLOCK_H */

View File

@ -0,0 +1,17 @@
#ifndef SMP_START_STOP_H
#define SMP_START_STOP_H
#if SMP == 1
#include <smp/atomic.h>
unsigned long this_processors_id(void);
int processor_index(unsigned long processor_id);
void stop_cpu(unsigned long processor_id);
int start_cpu(unsigned long processor_id);
void startup_other_cpus(unsigned long *processor_map);
#else
#define this_processors_id() 0
#define startup_other_cpus(p) do {} while(0)
#define processor_index(p) 0
#endif
#endif /* SMP_START_STOP_H */

14
src/include/stdlib.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef STDLIB_H
#define STDLIB_H
#include <stddef.h>
extern void *malloc(size_t size);
void free(void *ptr);
/* Extensions to malloc... */
typedef size_t malloc_mark_t;
void malloc_mark(malloc_mark_t *place);
void malloc_release(malloc_mark_t *place);
#endif /* STDLIB_H */

View File

@ -0,0 +1,13 @@
#ifndef STREAM_READ_BYTES_H
#define STREAM_READ_BYTES_H
#include <stdint.h>
typedef long byte_offset_t;
extern int stream_init(void);
extern byte_offset_t stream_read(void *vdest, byte_offset_t count);
extern byte_offset_t stream_skip(byte_offset_t count);
extern void stream_fini(void);
#endif /* STREAM_READ_BYTES_H */

36
src/include/string.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef STRING_H
#define STRING_H
#include <stddef.h>
// yes, linux has fancy ones. We don't care. This stuff gets used
// hardly at all. And the pain of including those files is just too high.
//extern inline void strcpy(char *dst, char *src) {while (*src) *dst++ = *src++;}
//extern inline int strlen(char *src) { int i = 0; while (*src++) i++; return i;}
static inline size_t strnlen(const char *src, size_t max)
{
size_t i = 0;
while((*src++) && (i < max)) {
i++;
}
return i;
}
static inline size_t strlen(const char *src)
{
size_t i = 0;
while(*src++) {
i++;
}
return i;
}
extern void *memcpy(void *dest, const void *src, size_t n);
extern void *memset(void *s, int c, size_t n);
extern int memcmp(const void *s1, const void *s2, size_t n);
extern int sprintf(char * buf, const char *fmt, ...);
#endif /* STRING_H */

7
src/include/uart8250.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef UART8250_H
#define UART8250_H
void uart8250_tx_byte(unsigned base_port, unsigned char data);
void uart8250_init(unsigned base_port, unsigned divisor, unsigned lcs);
#endif /* UART8250_H */

22
src/include/version.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef VERSION_H
#define VERSION_H
/* Motherboard Information */
extern const char mainboard_vendor[];
extern const char mainboard_part_number[];
/* LinuxBIOS Version */
extern const char linuxbios_version[];
extern const char linuxbios_extra_version[];
extern const char linuxbios_build[];
/* When LinuxBIOS was compiled */
extern const char linuxbios_compile_time[];
extern const char linuxbios_compile_by[];
extern const char linuxbios_compile_host[];
extern const char linuxbios_compile_domain[];
extern const char linuxbios_compiler[];
extern const char linuxbios_linker[];
extern const char linuxbios_assembler[];
#endif /* VERSION_H */

18
src/lib/clog2.c Normal file
View File

@ -0,0 +1,18 @@
#include <console/console.h>
unsigned long log2(unsigned long x)
{
// assume 8 bits per byte.
unsigned long i = 1 << (sizeof(x)*8 - 1);
unsigned long pow = sizeof(x) * 8 - 1;
if (! x) {
printk_warning("%s called with invalid parameter of 0\n",
__FUNCTION__);
return -1;
}
for(; i > x; i >>= 1, pow--)
;
return pow;
}

View File

@ -0,0 +1,53 @@
#include <stdint.h>
#include <ip_checksum.h>
unsigned long compute_ip_checksum(void *addr, unsigned long length)
{
uint8_t *ptr;
volatile union {
uint8_t byte[2];
uint16_t word;
} value;
unsigned long sum;
unsigned long i;
/* In the most straight forward way possible,
* compute an ip style checksum.
*/
sum = 0;
ptr = addr;
for(i = 0; i < length; i++) {
unsigned long value;
value = ptr[i];
if (i & 1) {
value <<= 8;
}
/* Add the new value */
sum += value;
/* Wrap around the carry */
if (sum > 0xFFFF) {
sum = (sum + (sum >> 16)) & 0xFFFF;
}
}
value.byte[0] = sum & 0xff;
value.byte[1] = (sum >> 8) & 0xff;
return (~value.word) & 0xFFFF;
}
unsigned long add_ip_checksums(unsigned long offset, unsigned long sum, unsigned long new)
{
unsigned long checksum;
sum = ~sum & 0xFFFF;
new = ~new & 0xFFFF;
if (offset & 1) {
/* byte swap the sum if it came from an odd offset
* since the computation is endian independant this
* works.
*/
new = ((new >> 8) & 0xff) | ((new << 8) & 0xff00);
}
checksum = sum + new;
if (checksum > 0xFFFF) {
checksum -= 0xFFFF;
}
return (~checksum) & 0xFFFF;
}

15
src/lib/delay.c Normal file
View File

@ -0,0 +1,15 @@
#include <delay.h>
void mdelay(int msecs)
{
int i;
for(i = 0; i < msecs; i++) {
udelay(1000);
}
}
void delay(int secs)
{
int i;
for(i = 0; i < secs; i++) {
mdelay(1000);
}
}

25
src/lib/fallback_boot.c Normal file
View File

@ -0,0 +1,25 @@
#include <console/console.h>
#include <part/fallback_boot.h>
#include <pc80/mc146818rtc.h>
#include <arch/io.h>
void boot_successful(void)
{
/* Remember I succesfully booted by setting
* the initial boot direction
* to the direction that I booted.
*/
unsigned char index, byte;
index = inb(RTC_PORT(0)) & 0x80;
index |= RTC_BOOT_BYTE;
outb(index, RTC_PORT(0));
byte = inb(RTC_PORT(1));
byte &= 0xfe;
byte |= (byte & 2) >> 1;
/* If we are in normal mode set the boot count to 0 */
if(byte & 1)
byte &= 0x0f;
outb(byte, RTC_PORT(1));
}

52
src/lib/malloc.c Normal file
View File

@ -0,0 +1,52 @@
#include <stdlib.h>
#include <console/console.h>
#if 0
#define MALLOCDBG(x)
#else
#define MALLOCDBG(x) printk_spew x
#endif
extern unsigned char _heap, _eheap;
static size_t free_mem_ptr = (size_t)&_heap; /* Start of heap */
static size_t free_mem_end_ptr = (size_t)&_eheap; /* End of heap */
void malloc_mark(malloc_mark_t *place)
{
*place = free_mem_ptr;
printk_spew("malloc_mark 0x%08lx\n", (unsigned long)free_mem_ptr);
}
void malloc_release(malloc_mark_t *ptr)
{
free_mem_ptr = *ptr;
printk_spew("malloc_release 0x%08lx\n", (unsigned long)free_mem_ptr);
}
void *malloc(size_t size)
{
void *p;
MALLOCDBG(("%s Enter, size %d, free_mem_ptr %p\n", __FUNCTION__, size, free_mem_ptr));
if (size < 0)
die("Error! malloc: Size < 0");
if (free_mem_ptr <= 0)
die("Error! malloc: Free_mem_ptr <= 0");
free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */
p = (void *) free_mem_ptr;
free_mem_ptr += size;
if (free_mem_ptr >= free_mem_end_ptr)
die("Error! malloc: Free_mem_ptr >= free_mem_end_ptr");
MALLOCDBG(("malloc 0x%08lx\n", (unsigned long)p));
return p;
}
void free(void *where)
{
/* Don't care */
}

17
src/lib/memcmp.c Normal file
View File

@ -0,0 +1,17 @@
#include <string.h>
int memcmp(const void *src1, const void *src2, size_t bytes)
{
const unsigned char *s1, *s2;
int result;
s1 = src1;
s2 = src2;
result = 0;
while((bytes > 0) && (result == 0)) {
result = *s1 - *s2;
bytes--;
s1++;
s2++;
}
return result;
}

11
src/lib/memcpy.c Normal file
View File

@ -0,0 +1,11 @@
#include <string.h>
void *memcpy(void *__dest, __const void *__src, size_t __n)
{
int i;
char *d = (char *) __dest, *s = (char *) __src;
for (i = 0; i < __n; i++)
d[i] = s[i];
return __dest;
}

12
src/lib/memset.c Normal file
View File

@ -0,0 +1,12 @@
#include <string.h>
void *memset(void *s, int c, size_t n)
{
int i;
char *ss = (char *) s;
for (i = 0; i < n; i++)
ss[i] = c;
return s;
}

64
src/lib/uart8250.c Normal file
View File

@ -0,0 +1,64 @@
#ifndef lint
static char rcsid[] = "$Id$";
#endif
/* Should support 8250, 16450, 16550, 16550A type uarts */
#include <arch/io.h>
#include <uart8250.h>
/* Data */
#define UART_RBR 0x00
#define UART_TBR 0x00
/* Control */
#define UART_IER 0x01
#define UART_IIR 0x02
#define UART_FCR 0x02
#define UART_LCR 0x03
#define UART_MCR 0x04
#define UART_DLL 0x00
#define UART_DLM 0x01
/* Status */
#define UART_LSR 0x05
#define UART_MSR 0x06
#define UART_SCR 0x07
static inline int uart8250_can_tx_byte(unsigned base_port)
{
return inb(base_port + UART_LSR) & 0x20;
}
static inline void uart8250_wait_to_tx_byte(unsigned base_port)
{
while(!uart8250_can_tx_byte(base_port))
;
}
static inline void uart8250_wait_until_sent(unsigned base_port)
{
while(!(inb(base_port + UART_LSR) & 0x40))
;
}
void uart8250_tx_byte(unsigned base_port, unsigned char data)
{
uart8250_wait_to_tx_byte(base_port);
outb(data, base_port + UART_TBR);
/* Make certain the data clears the fifos */
uart8250_wait_until_sent(base_port);
}
void uart8250_init(unsigned base_port, unsigned divisor, unsigned lcs)
{
lcs &= 0x7f;
/* disable interrupts */
outb(0x0, base_port + UART_IER);
/* enable fifo's */
outb(0x01, base_port + UART_FCR);
/* Set Baud Rate Divisor to 12 ==> 115200 Baud */
outb(0x80 | lcs, base_port + UART_LCR);
outb(divisor & 0xFF, base_port + UART_DLL);
outb((divisor >> 8) & 0xFF, base_port + UART_DLM);
outb(lcs, base_port + UART_LCR);
}

62
src/lib/version.c Normal file
View File

@ -0,0 +1,62 @@
#include <version.h>
#define __STR(X) #X
#define STR(X) __STR(X)
#ifndef MAINBOARD_VENDOR
#error MAINBOARD_VENDOR not defined
#endif
#ifndef MAINBOARD_PART_NUMBER
#error MAINBOARD_PART_NUMBER not defined
#endif
#ifndef LINUXBIOS_VERSION
#error LINUXBIOS_VERSION not defined
#endif
#ifndef LINUXBIOS_BUILD
#error LINUXBIOS_BUILD not defined
#endif
#ifndef LINUXBIOS_COMPILE_TIME
#error LINUXBIOS_COMPILE_TIME not defined
#endif
#ifndef LINUXBIOS_COMPILE_BY
#error LINUXBIOS_COMPILE_BY not defined
#endif
#ifndef LINUXBIOS_COMPILE_HOST
#error LINUXBIOS_COMPILE_HOST not defined
#endif
#ifndef LINUXBIOS_COMPILER
#error LINUXBIOS_COMPILER not defined
#endif
#ifndef LINUXBIOS_LINKER
#error LINUXBIOS_LINKER not defined
#endif
#ifndef LINUXBIOS_ASSEMBLER
#error LINUXBIOS_ASSEMBLER not defined
#endif
#ifndef LINUXBIOS_EXTRA_VERSION
#define LINUXBIOS_EXTRA_VERSION
#endif
const char mainboard_vendor[] = STR(MAINBOARD_VENDOR);
const char mainboard_part_number[] = STR(MAINBOARD_PART_NUMBER);
const char linuxbios_version[] = STR(LINUXBIOS_VERSION);
const char linuxbios_extra_version[] = STR(LINUXBIOS_EXTRA_VERSION);
const char linuxbios_build[] = STR(LINUXBIOS_BUILD);
const char linuxbios_compile_time[] = STR(LINUXBIOS_COMPILE_TIME);
const char linuxbios_compile_by[] = STR(LINUXBIOS_COMPILE_BY);
const char linuxbios_compile_host[] = STR(LINUXBIOS_COMPILE_HOST);
const char linuxbios_compile_domain[] = STR(LINUXBIOS_COMPILE_DOMAIN);
const char linuxbios_compiler[] = STR(LINUXBIOS_COMPILER);
const char linuxbios_linker[] = STR(LINUXBIOS_LINKER);
const char linuxbios_assembler[] = STR(LINUXBIOS_ASSEMBLER);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,74 @@
entries
#start-bit length config config-ID name
#0 8 r 0 seconds
#8 8 r 0 alarm_seconds
#16 8 r 0 minutes
#24 8 r 0 alarm_minutes
#32 8 r 0 hours
#40 8 r 0 alarm_hours
#48 8 r 0 day_of_week
#56 8 r 0 day_of_month
#64 8 r 0 month
#72 8 r 0 year
#80 4 r 0 rate_select
#84 3 r 0 REF_Clock
#87 1 r 0 UIP
#88 1 r 0 auto_switch_DST
#89 1 r 0 24_hour_mode
#90 1 r 0 binary_values_enable
#91 1 r 0 square-wave_out_enable
#92 1 r 0 update_finished_enable
#93 1 r 0 alarm_interrupt_enable
#94 1 r 0 periodic_interrupt_enable
#95 1 r 0 disable_clock_updates
#96 288 r 0 temporary_filler
0 384 r 0 reserved_memory
384 1 e 4 boot_option
385 1 e 4 last_boot
386 1 e 1 ECC_memory
388 4 r 0 reboot_bits
392 3 e 5 baud_rate
400 1 e 1 power_on_after_fail
412 4 e 6 debug_level
416 4 e 7 boot_first
420 4 e 7 boot_second
424 4 e 7 boot_third
428 4 h 0 boot_index
432 8 h 0 boot_countdown
1008 16 h 0 check_sum
enumerations
#ID value text
1 0 Disable
1 1 Enable
2 0 Enable
2 1 Disable
4 0 Fallback
4 1 Normal
5 0 115200
5 1 57600
5 2 38400
5 3 19200
5 4 9600
5 5 4800
5 6 2400
5 7 1200
6 6 Notice
6 7 Info
6 8 Debug
6 9 Spew
7 0 Network
7 1 HDD
7 2 Floppy
7 8 Fallback_Network
7 9 Fallback_HDD
7 10 Fallback_Floppy
#7 3 ROM
checksums
checksum 392 1007 1008

View File

@ -0,0 +1,25 @@
#if 0
#include <printk.h>
#endif
void
mainboard_fixup(void)
{
}
void
final_mainboard_fixup(void)
{
#if 0
// void final_southbridge_fixup(void);
// void final_superio_fixup(void);
printk_info("AMD Solo initializing...");
// final_southbridge_fixup();
//#ifndef USE_NEW_SUPERIO_INTERFACE
//final_superio_fixup();
//#endif
#endif
}

View File

@ -0,0 +1,22 @@
#include <arch/io.h>
#include <stdint.h>
#include <mem.h>
#include <part/sizeram.h>
struct mem_range *sizeram(void)
{
static struct mem_range mem[3];
uint32_t size;
/* Convert size in bytes to size in K */
/* FIXME hardcoded for now */
size = 512*1024;
mem[0].basek = 0;
mem[0].sizek = 640;
mem[1].basek = 1024;
mem[1].sizek = size - mem[1].basek;
mem[2].basek = 0;
mem[2].sizek = 0;
return mem;
}

249
src/pc80/mc146818rtc.c Normal file
View File

@ -0,0 +1,249 @@
#include <console/console.h>
#include <arch/io.h>
#include <pc80/mc146818rtc.h>
#include <boot/linuxbios_tables.h>
#include <string.h>
#define CMOS_READ(addr) ({ \
outb((addr),RTC_PORT(0)); \
inb(RTC_PORT(1)); \
})
#define CMOS_WRITE(val, addr) ({ \
outb((addr),RTC_PORT(0)); \
outb((val),RTC_PORT(1)); \
})
/* control registers - Moto names
*/
#define RTC_REG_A 10
#define RTC_REG_B 11
#define RTC_REG_C 12
#define RTC_REG_D 13
/**********************************************************************
* register details
**********************************************************************/
#define RTC_FREQ_SELECT RTC_REG_A
/* update-in-progress - set to "1" 244 microsecs before RTC goes off the bus,
* reset after update (may take 1.984ms @ 32768Hz RefClock) is complete,
* totalling to a max high interval of 2.228 ms.
*/
# define RTC_UIP 0x80
# define RTC_DIV_CTL 0x70
/* divider control: refclock values 4.194 / 1.049 MHz / 32.768 kHz */
# define RTC_REF_CLCK_4MHZ 0x00
# define RTC_REF_CLCK_1MHZ 0x10
# define RTC_REF_CLCK_32KHZ 0x20
/* 2 values for divider stage reset, others for "testing purposes only" */
# define RTC_DIV_RESET1 0x60
# define RTC_DIV_RESET2 0x70
/* Periodic intr. / Square wave rate select. 0=none, 1=32.8kHz,... 15=2Hz */
# define RTC_RATE_SELECT 0x0F
# define RTC_RATE_NONE 0x00
# define RTC_RATE_32786HZ 0x01
# define RTC_RATE_16384HZ 0x02
# define RTC_RATE_8192HZ 0x03
# define RTC_RATE_4096HZ 0x04
# define RTC_RATE_2048HZ 0x05
# define RTC_RATE_1024HZ 0x06
# define RTC_RATE_512HZ 0x07
# define RTC_RATE_256HZ 0x08
# define RTC_RATE_128HZ 0x09
# define RTC_RATE_64HZ 0x0a
# define RTC_RATE_32HZ 0x0b
# define RTC_RATE_16HZ 0x0c
# define RTC_RATE_8HZ 0x0d
# define RTC_RATE_4HZ 0x0e
# define RTC_RATE_2HZ 0x0f
/**********************************************************************/
#define RTC_CONTROL RTC_REG_B
# define RTC_SET 0x80 /* disable updates for clock setting */
# define RTC_PIE 0x40 /* periodic interrupt enable */
# define RTC_AIE 0x20 /* alarm interrupt enable */
# define RTC_UIE 0x10 /* update-finished interrupt enable */
# define RTC_SQWE 0x08 /* enable square-wave output */
# define RTC_DM_BINARY 0x04 /* all time/date values are BCD if clear */
# define RTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */
# define RTC_DST_EN 0x01 /* auto switch DST - works f. USA only */
/**********************************************************************/
#define RTC_INTR_FLAGS RTC_REG_C
/* caution - cleared by read */
# define RTC_IRQF 0x80 /* any of the following 3 is active */
# define RTC_PF 0x40
# define RTC_AF 0x20
# define RTC_UF 0x10
/**********************************************************************/
#define RTC_VALID RTC_REG_D
# define RTC_VRT 0x80 /* valid RAM and time */
/**********************************************************************/
static int rtc_checksum_valid(int range_start, int range_end, int cks_loc)
{
int i;
unsigned sum, old_sum;
sum = 0;
for(i = range_start; i <= range_end; i++) {
sum += CMOS_READ(i);
}
sum = (~sum)&0x0ffff;
old_sum = ((CMOS_READ(cks_loc)<<8) | CMOS_READ(cks_loc+1))&0x0ffff;
return sum == old_sum;
}
static void rtc_set_checksum(int range_start, int range_end, int cks_loc)
{
int i;
unsigned sum;
sum = 0;
for(i = range_start; i <= range_end; i++) {
sum += CMOS_READ(i);
}
sum = ~(sum & 0x0ffff);
CMOS_WRITE(((sum >> 8) & 0x0ff), cks_loc);
CMOS_WRITE(((sum >> 0) & 0x0ff), cks_loc+1);
}
#define RTC_CONTROL_DEFAULT (RTC_24H)
#define RTC_FREQ_SELECT_DEFAULT (RTC_REF_CLCK_32KHZ | RTC_RATE_1024HZ)
#if 0 /* alpha setup */
#undef RTC_CONTROL_DEFAULT
#undef RTC_FREQ_SELECT_DEFAULT
#define RTC_CONTROL_DEFAULT (RTC_SQWE | RTC_24H)
#define RTC_FREQ_SELECT_DEFAULT (RTC_REF_CLCK_32KHZ | RTC_RATE_1024HZ)
#endif
void rtc_init(int invalid)
{
unsigned char x;
int cmos_invalid, checksum_invalid;
printk_debug("RTC Init\n");
/* See if there has been a CMOS power problem. */
x = CMOS_READ(RTC_VALID);
cmos_invalid = !(x & RTC_VRT);
/* See if there is a CMOS checksum error */
checksum_invalid = !rtc_checksum_valid(PC_CKS_RANGE_START,
PC_CKS_RANGE_END,PC_CKS_LOC);
if (invalid || cmos_invalid || checksum_invalid) {
int i;
printk_warning("RTC:%s%s%s zeroing cmos\n",
invalid?" Clear requested":"",
cmos_invalid?" Power Problem":"",
checksum_invalid?" Checksum invalid":"");
#if 0
CMOS_WRITE(0, 0x01);
CMOS_WRITE(0, 0x03);
CMOS_WRITE(0, 0x05);
for(i = 10; i < 48; i++) {
CMOS_WRITE(0, i);
}
if (cmos_invalid) {
/* Now setup a default date of Sat 1 January 2000 */
CMOS_WRITE(0, 0x00); /* seconds */
CMOS_WRITE(0, 0x02); /* minutes */
CMOS_WRITE(1, 0x04); /* hours */
CMOS_WRITE(7, 0x06); /* day of week */
CMOS_WRITE(1, 0x07); /* day of month */
CMOS_WRITE(1, 0x08); /* month */
CMOS_WRITE(0, 0x09); /* year */
}
#endif
}
/* See if there is a LB CMOS checksum error */
checksum_invalid = !rtc_checksum_valid(LB_CKS_RANGE_START,
LB_CKS_RANGE_END,LB_CKS_LOC);
if(checksum_invalid)
printk_debug("Invalid CMOS LB checksum\n");
/* Setup the real time clock */
CMOS_WRITE(RTC_CONTROL_DEFAULT, RTC_CONTROL);
/* Setup the frequency it operates at */
CMOS_WRITE(RTC_FREQ_SELECT_DEFAULT, RTC_FREQ_SELECT);
/* Make certain we have a valid checksum */
rtc_set_checksum(PC_CKS_RANGE_START,
PC_CKS_RANGE_END,PC_CKS_LOC);
/* Clear any pending interrupts */
(void) CMOS_READ(RTC_INTR_FLAGS);
}
#if USE_OPTION_TABLE == 1
/* This routine returns the value of the requested bits
input bit = bit count from the beginning of the cmos image
length = number of bits to include in the value
ret = a character pointer to where the value is to be returned
output the value placed in ret
returns 0 = successful, -1 = an error occurred
*/
static int get_cmos_value(unsigned long bit, unsigned long length, void *vret)
{
unsigned char *ret;
unsigned long byte,byte_bit;
unsigned long i;
unsigned char uchar;
/* The table is checked when it is built to ensure all
values are valid. */
ret = vret;
byte=bit/8; /* find the byte where the data starts */
byte_bit=bit%8; /* find the bit in the byte where the data starts */
if(length<9) { /* one byte or less */
uchar = CMOS_READ(byte); /* load the byte */
uchar >>= byte_bit; /* shift the bits to byte align */
/* clear unspecified bits */
ret[0] = uchar & ((1 << length) -1);
}
else { /* more that one byte so transfer the whole bytes */
for(i=0;length;i++,length-=8,byte++) {
/* load the byte */
ret[i]=CMOS_READ(byte);
}
}
return 0;
}
int get_option(void *dest, char *name)
{
extern struct cmos_option_table option_table;
struct cmos_option_table *ct;
struct cmos_entries *ce;
size_t namelen;
int found=0;
/* Figure out how long name is */
namelen = strnlen(name, CMOS_MAX_NAME_LENGTH);
/* find the requested entry record */
ct=&option_table;
ce=(struct cmos_entries*)((unsigned char *)ct + ct->header_length);
for(;ce->tag==LB_TAG_OPTION;
ce=(struct cmos_entries*)((unsigned char *)ce + ce->size)) {
if (memcmp(ce->name, name, namelen) == 0) {
found=1;
break;
}
}
if(!found) {
printk_err("ERROR: No cmos option '%s'\n", name);
return(-2);
}
if(get_cmos_value(ce->bit, ce->length, dest))
return(-3);
if(!rtc_checksum_valid(LB_CKS_RANGE_START,
LB_CKS_RANGE_END,LB_CKS_LOC))
return(-4);
return(0);
}
#endif /* USE_OPTION_TABLE */

Some files were not shown because too many files have changed in this diff Show More