blob: 5da079ad04d4033199b5056eab08c3413a6ffcf3 [file] [log] [blame]
Kevin O'Connord25810a2008-06-12 22:16:35 -04001// PCI BIOS (int 1a/b1) calls
Kevin O'Connora0dc2962008-03-16 14:29:32 -04002//
3// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
4// Copyright (C) 2002 MandrakeSoft S.A.
5//
Kevin O'Connorb1b7c2a2009-01-15 20:52:58 -05006// This file may be distributed under the terms of the GNU LGPLv3 license.
Kevin O'Connora0dc2962008-03-16 14:29:32 -04007
8#include "types.h" // u32
9#include "util.h" // handle_1ab1
10#include "pci.h" // pci_config_readl
Kevin O'Connor9521e262008-07-04 13:04:29 -040011#include "bregs.h" // struct bregs
12#include "biosvar.h" // GET_EBDA
Kevin O'Connor4132e022008-12-04 19:39:10 -050013#include "pci_regs.h" // PCI_VENDOR_ID
Kevin O'Connora0dc2962008-03-16 14:29:32 -040014
Kevin O'Connora0dc2962008-03-16 14:29:32 -040015#define RET_FUNC_NOT_SUPPORTED 0x81
16#define RET_BAD_VENDOR_ID 0x83
17#define RET_DEVICE_NOT_FOUND 0x86
18#define RET_BUFFER_TOO_SMALL 0x89
19
20// installation check
21static void
22handle_1ab101(struct bregs *regs)
23{
Kevin O'Connore6338322008-11-29 20:31:49 -050024 // Find max bus.
25 int bdf, max;
Kevin O'Connor4132e022008-12-04 19:39:10 -050026 foreachpci(bdf, max) {
Kevin O'Connore6338322008-11-29 20:31:49 -050027 }
28
Kevin O'Connorcde7a582008-08-17 11:08:46 -040029 regs->al = 0x01; // Flags - "Config Mechanism #1" supported.
30 regs->bx = 0x0210; // PCI version 2.10
Kevin O'Connore6338322008-11-29 20:31:49 -050031 regs->cl = pci_bdf_to_bus(max - 1);
Kevin O'Connora0dc2962008-03-16 14:29:32 -040032 regs->edx = 0x20494350; // "PCI "
33 // XXX - bochs bios code sets edi to point to 32bit code - but no
34 // reference to this in spec.
Kevin O'Connorcde7a582008-08-17 11:08:46 -040035 set_code_success(regs);
Kevin O'Connora0dc2962008-03-16 14:29:32 -040036}
37
38// find pci device
39static void
40handle_1ab102(struct bregs *regs)
41{
Kevin O'Connor4132e022008-12-04 19:39:10 -050042 u32 id = (regs->cx << 16) | regs->dx;
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -050043 int count = regs->si;
Kevin O'Connor4132e022008-12-04 19:39:10 -050044 int bdf, max;
45 foreachpci(bdf, max) {
46 u32 v = pci_config_readl(bdf, PCI_VENDOR_ID);
47 if (v != id)
48 continue;
49 if (count--)
50 continue;
51 regs->bx = bdf;
52 set_code_success(regs);
53 return;
54 }
55 set_code_fail(regs, RET_DEVICE_NOT_FOUND);
Kevin O'Connora0dc2962008-03-16 14:29:32 -040056}
57
58// find class code
59static void
60handle_1ab103(struct bregs *regs)
61{
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -050062 int count = regs->si;
Kevin O'Connor4132e022008-12-04 19:39:10 -050063 u32 classprog = regs->ecx;
64 int bdf, max;
65 foreachpci(bdf, max) {
66 u32 v = pci_config_readl(bdf, PCI_CLASS_REVISION);
67 if ((v>>8) != classprog)
68 continue;
69 if (count--)
70 continue;
71 regs->bx = bdf;
72 set_code_success(regs);
73 return;
74 }
75 set_code_fail(regs, RET_DEVICE_NOT_FOUND);
Kevin O'Connora0dc2962008-03-16 14:29:32 -040076}
77
78// read configuration byte
79static void
80handle_1ab108(struct bregs *regs)
81{
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -050082 regs->cl = pci_config_readb(regs->bx, regs->di);
Kevin O'Connora0dc2962008-03-16 14:29:32 -040083 set_code_success(regs);
84}
85
86// read configuration word
87static void
88handle_1ab109(struct bregs *regs)
89{
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -050090 regs->cx = pci_config_readw(regs->bx, regs->di);
Kevin O'Connora0dc2962008-03-16 14:29:32 -040091 set_code_success(regs);
92}
93
94// read configuration dword
95static void
96handle_1ab10a(struct bregs *regs)
97{
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -050098 regs->ecx = pci_config_readl(regs->bx, regs->di);
Kevin O'Connora0dc2962008-03-16 14:29:32 -040099 set_code_success(regs);
100}
101
102// write configuration byte
103static void
104handle_1ab10b(struct bregs *regs)
105{
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -0500106 pci_config_writeb(regs->bx, regs->di, regs->cl);
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400107 set_code_success(regs);
108}
109
110// write configuration word
111static void
112handle_1ab10c(struct bregs *regs)
113{
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -0500114 pci_config_writew(regs->bx, regs->di, regs->cx);
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400115 set_code_success(regs);
116}
117
118// write configuration dword
119static void
120handle_1ab10d(struct bregs *regs)
121{
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -0500122 pci_config_writel(regs->bx, regs->di, regs->ecx);
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400123 set_code_success(regs);
124}
125
126// get irq routing options
127static void
128handle_1ab10e(struct bregs *regs)
129{
Kevin O'Connor51358db2008-12-28 21:50:29 -0500130 struct pir_header *pirtable_g = (void*)(GET_GLOBAL(PirOffset) + 0);
131 if (! pirtable_g) {
Kevin O'Connor0f803e42008-05-24 23:07:16 -0400132 set_code_fail(regs, RET_FUNC_NOT_SUPPORTED);
133 return;
134 }
135
Kevin O'Connord99908e2009-01-21 19:14:49 -0500136 struct param_s {
137 u16 size;
138 u16 buf_off;
139 u16 buf_seg;
140 } *param_far = (void*)(regs->di+0);
141
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400142 // Validate and update size.
Kevin O'Connord99908e2009-01-21 19:14:49 -0500143 u16 bufsize = GET_FARVAR(regs->es, param_far->size);
144 u16 pirsize = GET_GLOBAL(pirtable_g->size) - sizeof(struct pir_header);
145 SET_FARVAR(regs->es, param_far->size, pirsize);
146 if (bufsize < pirsize) {
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400147 set_code_fail(regs, RET_BUFFER_TOO_SMALL);
148 return;
149 }
150
151 // Get dest buffer.
Kevin O'Connord99908e2009-01-21 19:14:49 -0500152 void *buf_far = (void*)(GET_FARVAR(regs->es, param_far->buf_off)+0);
153 u16 buf_seg = GET_FARVAR(regs->es, param_far->buf_seg);
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400154
155 // Memcpy pir table slots to dest buffer.
Kevin O'Connord99908e2009-01-21 19:14:49 -0500156 memcpy_far(buf_seg, buf_far
Kevin O'Connor8b267cb2009-01-19 19:25:21 -0500157 , get_global_seg(), pirtable_g->slots
158 , pirsize);
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400159
160 // XXX - bochs bios sets bx to (1 << 9) | (1 << 11)
Kevin O'Connor51358db2008-12-28 21:50:29 -0500161 regs->bx = GET_GLOBAL(pirtable_g->exclusive_irqs);
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400162 set_code_success(regs);
163}
164
165static void
166handle_1ab1XX(struct bregs *regs)
167{
168 set_code_fail(regs, RET_FUNC_NOT_SUPPORTED);
169}
170
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400171void
172handle_1ab1(struct bregs *regs)
173{
174 //debug_stub(regs);
175
176 if (! CONFIG_PCIBIOS) {
177 set_fail(regs);
178 return;
179 }
180
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400181 switch (regs->al) {
182 case 0x01: handle_1ab101(regs); break;
183 case 0x02: handle_1ab102(regs); break;
184 case 0x03: handle_1ab103(regs); break;
185 case 0x08: handle_1ab108(regs); break;
186 case 0x09: handle_1ab109(regs); break;
187 case 0x0a: handle_1ab10a(regs); break;
188 case 0x0b: handle_1ab10b(regs); break;
189 case 0x0c: handle_1ab10c(regs); break;
190 case 0x0d: handle_1ab10d(regs); break;
191 case 0x0e: handle_1ab10e(regs); break;
192 default: handle_1ab1XX(regs); break;
193 }
194}