- 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);
}