- 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:
parent
b138ac83b5
commit
8ca8d7665d
182
src/arch/i386/boot/boot.c
Normal file
182
src/arch/i386/boot/boot.c
Normal 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)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
281
src/arch/i386/boot/linuxbios_table.c
Normal file
281
src/arch/i386/boot/linuxbios_table.c
Normal 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;
|
||||||
|
}
|
33
src/arch/i386/boot/linuxbios_table.h
Normal file
33
src/arch/i386/boot/linuxbios_table.h
Normal 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 */
|
93
src/arch/i386/boot/pirq_routing.c
Normal file
93
src/arch/i386/boot/pirq_routing.c
Normal 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;
|
||||||
|
}
|
69
src/arch/i386/boot/tables.c
Normal file
69
src/arch/i386/boot/tables.c
Normal 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();
|
||||||
|
}
|
30
src/arch/i386/include/arch/asm.h
Normal file
30
src/arch/i386/include/arch/asm.h
Normal 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 */
|
8
src/arch/i386/include/arch/boot/boot.h
Normal file
8
src/arch/i386/include/arch/boot/boot.h
Normal 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 */
|
369
src/arch/i386/include/arch/intel.h
Normal file
369
src/arch/i386/include/arch/intel.h
Normal 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 */
|
76
src/arch/i386/include/arch/io.h
Normal file
76
src/arch/i386/include/arch/io.h
Normal 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
|
||||||
|
|
9
src/arch/i386/include/arch/pciconf.h
Normal file
9
src/arch/i386/include/arch/pciconf.h
Normal 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
|
54
src/arch/i386/include/arch/pirq_routing.h
Normal file
54
src/arch/i386/include/arch/pirq_routing.h
Normal 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 */
|
10
src/arch/i386/include/arch/rom_segs.h
Normal file
10
src/arch/i386/include/arch/rom_segs.h
Normal 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 */
|
84
src/arch/i386/include/arch/romcc_io.h
Normal file
84
src/arch/i386/include/arch/romcc_io.h
Normal 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);
|
||||||
|
}
|
282
src/arch/i386/include/arch/smp/mpspec.h
Normal file
282
src/arch/i386/include/arch/smp/mpspec.h
Normal 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
|
||||||
|
|
20
src/arch/i386/include/bitops.h
Normal file
20
src/arch/i386/include/bitops.h
Normal 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 */
|
15
src/arch/i386/include/stddef.h
Normal file
15
src/arch/i386/include/stddef.h
Normal 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 */
|
52
src/arch/i386/include/stdint.h
Normal file
52
src/arch/i386/include/stdint.h
Normal 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
135
src/arch/i386/lib/c_start.S
Normal 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
119
src/arch/i386/lib/console.c
Normal 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);
|
||||||
|
}
|
527
src/arch/i386/lib/console.inc
Normal file
527
src/arch/i386/lib/console.inc
Normal 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
139
src/arch/i386/lib/cpu.c
Normal 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;
|
||||||
|
}
|
||||||
|
|
9
src/arch/i386/lib/cpu_reset.inc
Normal file
9
src/arch/i386/lib/cpu_reset.inc
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
jmp cpu_reset_out
|
||||||
|
|
||||||
|
__cpu_reset:
|
||||||
|
movl $0xffffffff, %ebp
|
||||||
|
jmp __main
|
||||||
|
|
||||||
|
cpu_reset_out:
|
||||||
|
|
||||||
|
|
1
src/arch/i386/lib/failover.lds
Normal file
1
src/arch/i386/lib/failover.lds
Normal file
@ -0,0 +1 @@
|
|||||||
|
__normal_image = (ZKERNEL_START & 0xfffffff0) - 8;
|
21
src/arch/i386/lib/id.inc
Normal file
21
src/arch/i386/lib/id.inc
Normal 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
6
src/arch/i386/lib/id.lds
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
SECTIONS {
|
||||||
|
. = (_ROMBASE + ROM_IMAGE_SIZE - 0x10) - (__id_end - __id_start);
|
||||||
|
.id (.): {
|
||||||
|
*(.id)
|
||||||
|
}
|
||||||
|
}
|
9
src/arch/i386/lib/noop_failover.inc
Normal file
9
src/arch/i386/lib/noop_failover.inc
Normal 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
281
src/arch/i386/lib/pci_ops.c
Normal 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
245
src/arch/i386/smp/mpspec.c
Normal 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
663
src/boot/elfboot.c
Normal 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
216
src/boot/hardwaremain.c
Normal 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
691
src/config/LinuxBIOSDoc.config
Executable 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
691
src/config/doxyscript.base
Executable 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
112
src/config/linuxbios_c.ld
Normal 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
75
src/console/console.c
Normal 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 */
|
||||||
|
}
|
19
src/console/logbuf_console.c
Normal file
19
src/console/logbuf_console.c
Normal 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
56
src/console/printk.c
Normal 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;
|
||||||
|
}
|
49
src/console/uart8250_console.c
Normal file
49
src/console/uart8250_console.c
Normal 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
100
src/console/vga_console.c
Normal 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
352
src/console/vsprintf.c
Normal 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
112
src/cpu/i386/entry16.inc
Normal 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
2
src/cpu/i386/entry16.lds
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
gdtptr16_offset = gdtptr16 & 0xffff;
|
||||||
|
_start_offset = _start & 0xffff;
|
55
src/cpu/i386/entry32.inc
Normal file
55
src/cpu/i386/entry32.inc
Normal 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
14
src/cpu/i386/entry32.lds
Normal 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
27
src/cpu/i386/reset16.inc
Normal 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
14
src/cpu/i386/reset16.lds
Normal 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
10
src/cpu/i386/reset32.inc
Normal 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
14
src/cpu/i386/reset32.lds
Normal 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
59
src/cpu/k8/cpufixup.c
Normal 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
99
src/cpu/k8/earlymtrr.inc
Normal 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
222
src/cpu/p5/cpuid.c
Normal 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
356
src/cpu/p6/mtrr.c
Normal 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
423
src/devices/device.c
Normal 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
56
src/devices/device_util.c
Normal 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
670
src/devices/pci_device.c
Normal 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
401
src/include/boot/elf.h
Normal 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 */
|
89
src/include/boot/elf_boot.h
Normal file
89
src/include/boot/elf_boot.h
Normal 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 */
|
183
src/include/boot/linuxbios_tables.h
Normal file
183
src/include/boot/linuxbios_tables.h
Normal 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 */
|
9
src/include/boot/tables.h
Normal file
9
src/include/boot/tables.h
Normal 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 */
|
76
src/include/console/console.h
Normal file
76
src/include/console/console.h
Normal 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_ */
|
30
src/include/console/loglevel.h
Normal file
30
src/include/console/loglevel.h
Normal 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
11
src/include/cpu/cpu.h
Normal 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 */
|
24
src/include/cpu/cpufixup.h
Normal file
24
src/include/cpu/cpufixup.h
Normal 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 */
|
6
src/include/cpu/k7/cpufixup.h
Normal file
6
src/include/cpu/k7/cpufixup.h
Normal 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
42
src/include/cpu/k7/mtrr.h
Normal 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 */
|
6
src/include/cpu/k8/cpufixup.h
Normal file
6
src/include/cpu/k8/cpufixup.h
Normal 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
45
src/include/cpu/k8/mtrr.h
Normal 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 */
|
25
src/include/cpu/p5/cpuid.h
Normal file
25
src/include/cpu/p5/cpuid.h
Normal 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
175
src/include/cpu/p6/apic.h
Normal 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 */
|
6
src/include/cpu/p6/cpufixup.h
Normal file
6
src/include/cpu/p6/cpufixup.h
Normal 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
33
src/include/cpu/p6/msr.h
Normal 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
44
src/include/cpu/p6/mtrr.h
Normal 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
8
src/include/delay.h
Normal 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 */
|
7
src/include/ip_checksum.h
Normal file
7
src/include/ip_checksum.h
Normal 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
13
src/include/mem.h
Normal 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 */
|
16
src/include/part/fallback_boot.h
Normal file
16
src/include/part/fallback_boot.h
Normal 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 */
|
7
src/include/part/sizeram.h
Normal file
7
src/include/part/sizeram.h
Normal 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 */
|
110
src/include/pc80/mc146818rtc.h
Normal file
110
src/include/pc80/mc146818rtc.h
Normal 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
53
src/include/smp/atomic.h
Normal 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 */
|
24
src/include/smp/spinlock.h
Normal file
24
src/include/smp/spinlock.h
Normal 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 */
|
17
src/include/smp/start_stop.h
Normal file
17
src/include/smp/start_stop.h
Normal 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
14
src/include/stdlib.h
Normal 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 */
|
13
src/include/stream/read_bytes.h
Normal file
13
src/include/stream/read_bytes.h
Normal 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
36
src/include/string.h
Normal 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
7
src/include/uart8250.h
Normal 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
22
src/include/version.h
Normal 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
18
src/lib/clog2.c
Normal 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;
|
||||||
|
}
|
53
src/lib/compute_ip_checksum.c
Normal file
53
src/lib/compute_ip_checksum.c
Normal 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
15
src/lib/delay.c
Normal 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
25
src/lib/fallback_boot.c
Normal 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
52
src/lib/malloc.c
Normal 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
17
src/lib/memcmp.c
Normal 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
11
src/lib/memcpy.c
Normal 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
12
src/lib/memset.c
Normal 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
64
src/lib/uart8250.c
Normal 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
62
src/lib/version.c
Normal 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);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
1070
src/mainboard/amd/solo/auto.c
Normal file
1070
src/mainboard/amd/solo/auto.c
Normal file
File diff suppressed because it is too large
Load Diff
74
src/mainboard/amd/solo/cmos.layout
Normal file
74
src/mainboard/amd/solo/cmos.layout
Normal 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
|
||||||
|
|
||||||
|
|
25
src/mainboard/amd/solo/mainboard.c
Normal file
25
src/mainboard/amd/solo/mainboard.c
Normal 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
|
||||||
|
}
|
22
src/northbridge/amd/amdk8/northbridge.c
Normal file
22
src/northbridge/amd/amdk8/northbridge.c
Normal 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
249
src/pc80/mc146818rtc.c
Normal 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
Loading…
x
Reference in New Issue
Block a user