Kevin O'Connor | da4a648 | 2008-06-08 13:48:06 -0400 | [diff] [blame] | 1 | // Support for enabling/disabling BIOS ram shadowing. |
| 2 | // |
Kevin O'Connor | e773930 | 2009-07-26 19:16:09 -0400 | [diff] [blame] | 3 | // Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net> |
Kevin O'Connor | da4a648 | 2008-06-08 13:48:06 -0400 | [diff] [blame] | 4 | // Copyright (C) 2006 Fabrice Bellard |
| 5 | // |
Kevin O'Connor | b1b7c2a | 2009-01-15 20:52:58 -0500 | [diff] [blame] | 6 | // This file may be distributed under the terms of the GNU LGPLv3 license. |
Kevin O'Connor | da4a648 | 2008-06-08 13:48:06 -0400 | [diff] [blame] | 7 | |
| 8 | #include "util.h" // memcpy |
| 9 | #include "pci.h" // pci_config_writeb |
Kevin O'Connor | 9521e26 | 2008-07-04 13:04:29 -0400 | [diff] [blame] | 10 | #include "config.h" // CONFIG_* |
Kevin O'Connor | 2ed2f58 | 2008-11-08 15:53:36 -0500 | [diff] [blame] | 11 | #include "pci_ids.h" // PCI_VENDOR_ID_INTEL |
Kevin O'Connor | da4a648 | 2008-06-08 13:48:06 -0400 | [diff] [blame] | 12 | |
Kevin O'Connor | da4a648 | 2008-06-08 13:48:06 -0400 | [diff] [blame] | 13 | // Test if 'addr' is in the range from 'start'..'start+size' |
| 14 | #define IN_RANGE(addr, start, size) ({ \ |
| 15 | u32 __addr = (addr); \ |
| 16 | u32 __start = (start); \ |
| 17 | u32 __size = (size); \ |
| 18 | (__addr - __start < __size); \ |
| 19 | }) |
| 20 | |
Kevin O'Connor | 3528496 | 2009-07-24 21:49:26 -0400 | [diff] [blame] | 21 | // On the emulators, the bios at 0xf0000 is also at 0xffff0000 |
| 22 | #define BIOS_SRC_ADDR 0xffff0000 |
| 23 | |
Kevin O'Connor | da4a648 | 2008-06-08 13:48:06 -0400 | [diff] [blame] | 24 | // Enable shadowing and copy bios. |
| 25 | static void |
Kevin O'Connor | e773930 | 2009-07-26 19:16:09 -0400 | [diff] [blame] | 26 | copy_bios(u16 bdf) |
Kevin O'Connor | da4a648 | 2008-06-08 13:48:06 -0400 | [diff] [blame] | 27 | { |
Kevin O'Connor | e773930 | 2009-07-26 19:16:09 -0400 | [diff] [blame] | 28 | pci_config_writeb(bdf, 0x59, 0x30); |
Kevin O'Connor | 3528496 | 2009-07-24 21:49:26 -0400 | [diff] [blame] | 29 | memcpy((void*)BUILD_BIOS_ADDR, (void*)BIOS_SRC_ADDR, BUILD_BIOS_SIZE); |
Kevin O'Connor | da4a648 | 2008-06-08 13:48:06 -0400 | [diff] [blame] | 30 | } |
| 31 | |
Kevin O'Connor | e773930 | 2009-07-26 19:16:09 -0400 | [diff] [blame] | 32 | // Make the 0xc0000-0x100000 area read/writable. |
Kevin O'Connor | da4a648 | 2008-06-08 13:48:06 -0400 | [diff] [blame] | 33 | void |
| 34 | make_bios_writable() |
| 35 | { |
| 36 | if (CONFIG_COREBOOT) |
| 37 | return; |
| 38 | |
| 39 | dprintf(3, "enabling shadow ram\n"); |
| 40 | |
| 41 | // Locate chip controlling ram shadowing. |
Kevin O'Connor | 4132e02 | 2008-12-04 19:39:10 -0500 | [diff] [blame] | 42 | int bdf = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441); |
Kevin O'Connor | be19cdc | 2008-11-09 15:33:47 -0500 | [diff] [blame] | 43 | if (bdf < 0) { |
Kevin O'Connor | da4a648 | 2008-06-08 13:48:06 -0400 | [diff] [blame] | 44 | dprintf(1, "Unable to unlock ram - bridge not found\n"); |
| 45 | return; |
| 46 | } |
| 47 | |
Kevin O'Connor | e773930 | 2009-07-26 19:16:09 -0400 | [diff] [blame] | 48 | // Make ram from 0xc0000-0xf0000 writable |
| 49 | int clear = 0; |
| 50 | int i; |
| 51 | for (i=0; i<6; i++) { |
| 52 | if (CONFIG_OPTIONROMS_DEPLOYED) { |
| 53 | int reg = pci_config_readb(bdf, 0x5a + i); |
| 54 | if ((reg & 0x11) != 0x11) { |
| 55 | // Need to copy optionroms to work around qemu implementation |
| 56 | void *mem = (void*)(BUILD_ROM_START + i * 32*1024); |
| 57 | memcpy((void*)BUILD_BIOS_TMP_ADDR, mem, 32*1024); |
| 58 | pci_config_writeb(bdf, 0x5a + i, 0x33); |
| 59 | memcpy(mem, (void*)BUILD_BIOS_TMP_ADDR, 32*1024); |
| 60 | clear = 1; |
| 61 | } else { |
| 62 | pci_config_writeb(bdf, 0x5a + i, 0x33); |
| 63 | } |
| 64 | } else { |
| 65 | pci_config_writeb(bdf, 0x5a + i, 0x33); |
| 66 | } |
| 67 | } |
| 68 | if (clear) |
| 69 | memset((void*)BUILD_BIOS_TMP_ADDR, 0, 32*1024); |
| 70 | |
Kevin O'Connor | 3528496 | 2009-07-24 21:49:26 -0400 | [diff] [blame] | 71 | int reg = pci_config_readb(bdf, 0x59); |
Kevin O'Connor | e773930 | 2009-07-26 19:16:09 -0400 | [diff] [blame] | 72 | if (reg & 0x10) { |
Kevin O'Connor | 3528496 | 2009-07-24 21:49:26 -0400 | [diff] [blame] | 73 | // Ram already present - just enable writes |
Kevin O'Connor | e773930 | 2009-07-26 19:16:09 -0400 | [diff] [blame] | 74 | pci_config_writeb(bdf, 0x59, 0x30); |
Kevin O'Connor | 3528496 | 2009-07-24 21:49:26 -0400 | [diff] [blame] | 75 | return; |
| 76 | } |
Kevin O'Connor | da4a648 | 2008-06-08 13:48:06 -0400 | [diff] [blame] | 77 | |
| 78 | // Enable shadowing and copy bios. |
Kevin O'Connor | e3677b1 | 2008-07-04 15:29:23 -0400 | [diff] [blame] | 79 | if (IN_RANGE((u32)copy_bios, BUILD_BIOS_ADDR, BUILD_BIOS_SIZE)) { |
Kevin O'Connor | da4a648 | 2008-06-08 13:48:06 -0400 | [diff] [blame] | 80 | // Jump to shadow enable function - use the copy in the |
| 81 | // temporary storage area so that memory does not change under |
| 82 | // the executing code. |
Kevin O'Connor | 3528496 | 2009-07-24 21:49:26 -0400 | [diff] [blame] | 83 | u32 pos = (u32)copy_bios - BUILD_BIOS_ADDR + BIOS_SRC_ADDR; |
Kevin O'Connor | e773930 | 2009-07-26 19:16:09 -0400 | [diff] [blame] | 84 | void (*func)(u16 bdf) = (void*)pos; |
| 85 | func(bdf); |
Kevin O'Connor | da4a648 | 2008-06-08 13:48:06 -0400 | [diff] [blame] | 86 | } else { |
Kevin O'Connor | e773930 | 2009-07-26 19:16:09 -0400 | [diff] [blame] | 87 | copy_bios(bdf); |
Kevin O'Connor | da4a648 | 2008-06-08 13:48:06 -0400 | [diff] [blame] | 88 | } |
Kevin O'Connor | da4a648 | 2008-06-08 13:48:06 -0400 | [diff] [blame] | 89 | } |
| 90 | |
| 91 | // Make the BIOS code segment area (0xf0000) read-only. |
| 92 | void |
| 93 | make_bios_readonly() |
| 94 | { |
| 95 | if (CONFIG_COREBOOT) |
| 96 | return; |
| 97 | |
| 98 | dprintf(3, "locking shadow ram\n"); |
| 99 | |
Kevin O'Connor | 4132e02 | 2008-12-04 19:39:10 -0500 | [diff] [blame] | 100 | int bdf = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441); |
Kevin O'Connor | be19cdc | 2008-11-09 15:33:47 -0500 | [diff] [blame] | 101 | if (bdf < 0) { |
Kevin O'Connor | da4a648 | 2008-06-08 13:48:06 -0400 | [diff] [blame] | 102 | dprintf(1, "Unable to lock ram - bridge not found\n"); |
| 103 | return; |
| 104 | } |
| 105 | |
Kevin O'Connor | e773930 | 2009-07-26 19:16:09 -0400 | [diff] [blame] | 106 | // Flush any pending writes before locking memory. |
Kevin O'Connor | da4a648 | 2008-06-08 13:48:06 -0400 | [diff] [blame] | 107 | wbinvd(); |
Kevin O'Connor | e773930 | 2009-07-26 19:16:09 -0400 | [diff] [blame] | 108 | |
| 109 | // Write protect roms from 0xc0000-0xf0000 |
| 110 | int i; |
| 111 | for (i=0; i<6; i++) { |
| 112 | u32 mem = BUILD_ROM_START + i * 32*1024; |
| 113 | if (RomEnd <= mem + 16*1024) { |
| 114 | if (RomEnd > mem) |
| 115 | pci_config_writeb(bdf, 0x5a + i, 0x31); |
| 116 | break; |
| 117 | } |
| 118 | pci_config_writeb(bdf, 0x5a + i, 0x11); |
| 119 | } |
| 120 | |
| 121 | // Write protect 0xf0000-0x100000 |
| 122 | pci_config_writeb(bdf, 0x59, 0x10); |
Kevin O'Connor | da4a648 | 2008-06-08 13:48:06 -0400 | [diff] [blame] | 123 | } |