diff options
author | Eric Biederman <ebiederm@xmission.com> | 2003-04-22 19:02:15 +0000 |
---|---|---|
committer | Eric Biederman <ebiederm@xmission.com> | 2003-04-22 19:02:15 +0000 |
commit | 8ca8d7665d671e10d72b8fcb4d69121d75f7906e (patch) | |
tree | daad2699b4e6b6014bce5a76e82dd9c974801777 /src/arch/i386/lib | |
parent | b138ac83b53da9abf3dc9a87a1cd4b3d3a8150bd (diff) | |
download | coreboot-8ca8d7665d671e10d72b8fcb4d69121d75f7906e.tar.xz |
- Initial checkin of the freebios2 tree
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@784 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src/arch/i386/lib')
-rw-r--r-- | src/arch/i386/lib/c_start.S | 135 | ||||
-rw-r--r-- | src/arch/i386/lib/console.c | 119 | ||||
-rw-r--r-- | src/arch/i386/lib/console.inc | 527 | ||||
-rw-r--r-- | src/arch/i386/lib/cpu.c | 139 | ||||
-rw-r--r-- | src/arch/i386/lib/cpu_reset.inc | 9 | ||||
-rw-r--r-- | src/arch/i386/lib/failover.lds | 1 | ||||
-rw-r--r-- | src/arch/i386/lib/id.inc | 21 | ||||
-rw-r--r-- | src/arch/i386/lib/id.lds | 6 | ||||
-rw-r--r-- | src/arch/i386/lib/noop_failover.inc | 9 | ||||
-rw-r--r-- | src/arch/i386/lib/pci_ops.c | 281 |
10 files changed, 1247 insertions, 0 deletions
diff --git a/src/arch/i386/lib/c_start.S b/src/arch/i386/lib/c_start.S new file mode 100644 index 0000000000..f5ca3388f8 --- /dev/null +++ b/src/arch/i386/lib/c_start.S @@ -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 diff --git a/src/arch/i386/lib/console.c b/src/arch/i386/lib/console.c new file mode 100644 index 0000000000..8c8eccdd2a --- /dev/null +++ b/src/arch/i386/lib/console.c @@ -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); +} diff --git a/src/arch/i386/lib/console.inc b/src/arch/i386/lib/console.inc new file mode 100644 index 0000000000..3d6b01b3a2 --- /dev/null +++ b/src/arch/i386/lib/console.inc @@ -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) + diff --git a/src/arch/i386/lib/cpu.c b/src/arch/i386/lib/cpu.c new file mode 100644 index 0000000000..3e27e7acdc --- /dev/null +++ b/src/arch/i386/lib/cpu.c @@ -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; +} + diff --git a/src/arch/i386/lib/cpu_reset.inc b/src/arch/i386/lib/cpu_reset.inc new file mode 100644 index 0000000000..c7c05e2198 --- /dev/null +++ b/src/arch/i386/lib/cpu_reset.inc @@ -0,0 +1,9 @@ +jmp cpu_reset_out + +__cpu_reset: + movl $0xffffffff, %ebp + jmp __main + +cpu_reset_out: + + diff --git a/src/arch/i386/lib/failover.lds b/src/arch/i386/lib/failover.lds new file mode 100644 index 0000000000..c9cf7298f8 --- /dev/null +++ b/src/arch/i386/lib/failover.lds @@ -0,0 +1 @@ + __normal_image = (ZKERNEL_START & 0xfffffff0) - 8; diff --git a/src/arch/i386/lib/id.inc b/src/arch/i386/lib/id.inc new file mode 100644 index 0000000000..f28e23a2e8 --- /dev/null +++ b/src/arch/i386/lib/id.inc @@ -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 diff --git a/src/arch/i386/lib/id.lds b/src/arch/i386/lib/id.lds new file mode 100644 index 0000000000..ccdf7008f7 --- /dev/null +++ b/src/arch/i386/lib/id.lds @@ -0,0 +1,6 @@ +SECTIONS { + . = (_ROMBASE + ROM_IMAGE_SIZE - 0x10) - (__id_end - __id_start); + .id (.): { + *(.id) + } +} diff --git a/src/arch/i386/lib/noop_failover.inc b/src/arch/i386/lib/noop_failover.inc new file mode 100644 index 0000000000..70c10b0d3e --- /dev/null +++ b/src/arch/i386/lib/noop_failover.inc @@ -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 diff --git a/src/arch/i386/lib/pci_ops.c b/src/arch/i386/lib/pci_ops.c new file mode 100644 index 0000000000..80921bf9da --- /dev/null +++ b/src/arch/i386/lib/pci_ops.c @@ -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(); +} + + |