Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


imported SEABIOS source tree
[palacios.git] / bios / seabios / src / pcibios.c
1 // PCI BIOS (int 1a/b1) calls
2 //
3 // Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
4 // Copyright (C) 2002  MandrakeSoft S.A.
5 //
6 // This file may be distributed under the terms of the GNU LGPLv3 license.
7
8 #include "types.h" // u32
9 #include "util.h" // handle_1ab1
10 #include "pci.h" // pci_config_readl
11 #include "bregs.h" // struct bregs
12 #include "biosvar.h" // GET_EBDA
13 #include "pci_regs.h" // PCI_VENDOR_ID
14
15 // romlayout.S
16 extern void entry_bios32(void);
17 extern void entry_pcibios32(void);
18
19 #define RET_FUNC_NOT_SUPPORTED 0x81
20 #define RET_BAD_VENDOR_ID      0x83
21 #define RET_DEVICE_NOT_FOUND   0x86
22 #define RET_BUFFER_TOO_SMALL   0x89
23
24 // installation check
25 static void
26 handle_1ab101(struct bregs *regs)
27 {
28     regs->al = 0x01; // Flags - "Config Mechanism #1" supported.
29     regs->bx = 0x0210; // PCI version 2.10
30     regs->cl = GET_GLOBAL(MaxPCIBus);
31     regs->edx = 0x20494350; // "PCI "
32     regs->edi = (u32)entry_pcibios32 + BUILD_BIOS_ADDR;
33     set_code_success(regs);
34 }
35
36 // find pci device
37 static void
38 handle_1ab102(struct bregs *regs)
39 {
40     u32 id = (regs->cx << 16) | regs->dx;
41     int count = regs->si;
42     int bus = -1;
43     while (bus < GET_GLOBAL(MaxPCIBus)) {
44         bus++;
45         int bdf;
46         foreachbdf(bdf, bus) {
47             u32 v = pci_config_readl(bdf, PCI_VENDOR_ID);
48             if (v != id)
49                 continue;
50             if (count--)
51                 continue;
52             regs->bx = bdf;
53             set_code_success(regs);
54             return;
55         }
56     }
57     set_code_invalid(regs, RET_DEVICE_NOT_FOUND);
58 }
59
60 // find class code
61 static void
62 handle_1ab103(struct bregs *regs)
63 {
64     int count = regs->si;
65     u32 classprog = regs->ecx;
66     int bus = -1;
67     while (bus < GET_GLOBAL(MaxPCIBus)) {
68         bus++;
69         int bdf;
70         foreachbdf(bdf, bus) {
71             u32 v = pci_config_readl(bdf, PCI_CLASS_REVISION);
72             if ((v>>8) != classprog)
73                 continue;
74             if (count--)
75                 continue;
76             regs->bx = bdf;
77             set_code_success(regs);
78             return;
79         }
80     }
81     set_code_invalid(regs, RET_DEVICE_NOT_FOUND);
82 }
83
84 // read configuration byte
85 static void
86 handle_1ab108(struct bregs *regs)
87 {
88     regs->cl = pci_config_readb(regs->bx, regs->di);
89     set_code_success(regs);
90 }
91
92 // read configuration word
93 static void
94 handle_1ab109(struct bregs *regs)
95 {
96     regs->cx = pci_config_readw(regs->bx, regs->di);
97     set_code_success(regs);
98 }
99
100 // read configuration dword
101 static void
102 handle_1ab10a(struct bregs *regs)
103 {
104     regs->ecx = pci_config_readl(regs->bx, regs->di);
105     set_code_success(regs);
106 }
107
108 // write configuration byte
109 static void
110 handle_1ab10b(struct bregs *regs)
111 {
112     pci_config_writeb(regs->bx, regs->di, regs->cl);
113     set_code_success(regs);
114 }
115
116 // write configuration word
117 static void
118 handle_1ab10c(struct bregs *regs)
119 {
120     pci_config_writew(regs->bx, regs->di, regs->cx);
121     set_code_success(regs);
122 }
123
124 // write configuration dword
125 static void
126 handle_1ab10d(struct bregs *regs)
127 {
128     pci_config_writel(regs->bx, regs->di, regs->ecx);
129     set_code_success(regs);
130 }
131
132 // get irq routing options
133 static void
134 handle_1ab10e(struct bregs *regs)
135 {
136     struct pir_header *pirtable_g = (void*)(GET_GLOBAL(PirOffset) + 0);
137     if (! pirtable_g) {
138         set_code_invalid(regs, RET_FUNC_NOT_SUPPORTED);
139         return;
140     }
141
142     struct param_s {
143         u16 size;
144         u16 buf_off;
145         u16 buf_seg;
146     } *param_far = (void*)(regs->di+0);
147
148     // Validate and update size.
149     u16 bufsize = GET_FARVAR(regs->es, param_far->size);
150     u16 pirsize = GET_GLOBAL(pirtable_g->size) - sizeof(struct pir_header);
151     SET_FARVAR(regs->es, param_far->size, pirsize);
152     if (bufsize < pirsize) {
153         set_code_invalid(regs, RET_BUFFER_TOO_SMALL);
154         return;
155     }
156
157     // Get dest buffer.
158     void *buf_far = (void*)(GET_FARVAR(regs->es, param_far->buf_off)+0);
159     u16 buf_seg = GET_FARVAR(regs->es, param_far->buf_seg);
160
161     // Memcpy pir table slots to dest buffer.
162     memcpy_far(buf_seg, buf_far
163                , get_global_seg()
164                , (void*)(pirtable_g->slots) + get_global_offset()
165                , pirsize);
166
167     // XXX - bochs bios sets bx to (1 << 9) | (1 << 11)
168     regs->bx = GET_GLOBAL(pirtable_g->exclusive_irqs);
169     set_code_success(regs);
170 }
171
172 static void
173 handle_1ab1XX(struct bregs *regs)
174 {
175     set_code_unimplemented(regs, RET_FUNC_NOT_SUPPORTED);
176 }
177
178 void
179 handle_1ab1(struct bregs *regs)
180 {
181     //debug_stub(regs);
182
183     if (! CONFIG_PCIBIOS) {
184         set_invalid(regs);
185         return;
186     }
187
188     switch (regs->al) {
189     case 0x01: handle_1ab101(regs); break;
190     case 0x02: handle_1ab102(regs); break;
191     case 0x03: handle_1ab103(regs); break;
192     case 0x08: handle_1ab108(regs); break;
193     case 0x09: handle_1ab109(regs); break;
194     case 0x0a: handle_1ab10a(regs); break;
195     case 0x0b: handle_1ab10b(regs); break;
196     case 0x0c: handle_1ab10c(regs); break;
197     case 0x0d: handle_1ab10d(regs); break;
198     case 0x0e: handle_1ab10e(regs); break;
199     default:   handle_1ab1XX(regs); break;
200     }
201 }
202
203
204 /****************************************************************
205  * 32bit interface
206  ****************************************************************/
207
208 // Entry point for 32bit pci bios functions.
209 void VISIBLE32SEG
210 handle_pcibios32(struct bregs *regs)
211 {
212     debug_enter(regs, DEBUG_HDL_pcibios32);
213     handle_1ab1(regs);
214 }
215
216 struct bios32_s {
217     u32 signature;
218     u32 entry;
219     u8 version;
220     u8 length;
221     u8 checksum;
222     u8 reserved[5];
223 } PACKED;
224
225 struct bios32_s BIOS32HEADER __aligned(16) VAR16EXPORT = {
226     .signature = 0x5f32335f, // _32_
227     .length = sizeof(BIOS32HEADER) / 16,
228 };
229
230 void
231 bios32_setup(void)
232 {
233     dprintf(3, "init bios32\n");
234
235     BIOS32HEADER.entry = (u32)entry_bios32;
236     BIOS32HEADER.checksum -= checksum(&BIOS32HEADER, sizeof(BIOS32HEADER));
237 }