blob: 4fdfd5e58003d16a0e814e7f3a4be4941715e0ff [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'Connor871e0a02009-12-30 12:14:53 -050015// romlayout.S
Kevin O'Connor1ca05b02010-01-03 17:43:37 -050016extern void bios32_entry(void);
17extern void pcibios32_entry(void);
Kevin O'Connor871e0a02009-12-30 12:14:53 -050018
Kevin O'Connora0dc2962008-03-16 14:29:32 -040019#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
25static void
26handle_1ab101(struct bregs *regs)
27{
Kevin O'Connore6338322008-11-29 20:31:49 -050028 // Find max bus.
29 int bdf, max;
Kevin O'Connorbaac6b62011-06-19 10:46:28 -040030 foreachbdf(bdf, max) {
Kevin O'Connore6338322008-11-29 20:31:49 -050031 }
32
Kevin O'Connorcde7a582008-08-17 11:08:46 -040033 regs->al = 0x01; // Flags - "Config Mechanism #1" supported.
34 regs->bx = 0x0210; // PCI version 2.10
Kevin O'Connore6338322008-11-29 20:31:49 -050035 regs->cl = pci_bdf_to_bus(max - 1);
Kevin O'Connora0dc2962008-03-16 14:29:32 -040036 regs->edx = 0x20494350; // "PCI "
Kevin O'Connor871e0a02009-12-30 12:14:53 -050037 regs->edi = (u32)pcibios32_entry + BUILD_BIOS_ADDR;
Kevin O'Connorcde7a582008-08-17 11:08:46 -040038 set_code_success(regs);
Kevin O'Connora0dc2962008-03-16 14:29:32 -040039}
40
41// find pci device
42static void
43handle_1ab102(struct bregs *regs)
44{
Kevin O'Connor4132e022008-12-04 19:39:10 -050045 u32 id = (regs->cx << 16) | regs->dx;
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -050046 int count = regs->si;
Kevin O'Connor4132e022008-12-04 19:39:10 -050047 int bdf, max;
Kevin O'Connorbaac6b62011-06-19 10:46:28 -040048 foreachbdf(bdf, max) {
Kevin O'Connor4132e022008-12-04 19:39:10 -050049 u32 v = pci_config_readl(bdf, PCI_VENDOR_ID);
50 if (v != id)
51 continue;
52 if (count--)
53 continue;
54 regs->bx = bdf;
55 set_code_success(regs);
56 return;
57 }
Kevin O'Connordfefeb52009-12-13 13:04:17 -050058 set_code_invalid(regs, RET_DEVICE_NOT_FOUND);
Kevin O'Connora0dc2962008-03-16 14:29:32 -040059}
60
61// find class code
62static void
63handle_1ab103(struct bregs *regs)
64{
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -050065 int count = regs->si;
Kevin O'Connor4132e022008-12-04 19:39:10 -050066 u32 classprog = regs->ecx;
67 int bdf, max;
Kevin O'Connorbaac6b62011-06-19 10:46:28 -040068 foreachbdf(bdf, max) {
Kevin O'Connor4132e022008-12-04 19:39:10 -050069 u32 v = pci_config_readl(bdf, PCI_CLASS_REVISION);
70 if ((v>>8) != classprog)
71 continue;
72 if (count--)
73 continue;
74 regs->bx = bdf;
75 set_code_success(regs);
76 return;
77 }
Kevin O'Connordfefeb52009-12-13 13:04:17 -050078 set_code_invalid(regs, RET_DEVICE_NOT_FOUND);
Kevin O'Connora0dc2962008-03-16 14:29:32 -040079}
80
81// read configuration byte
82static void
83handle_1ab108(struct bregs *regs)
84{
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -050085 regs->cl = pci_config_readb(regs->bx, regs->di);
Kevin O'Connora0dc2962008-03-16 14:29:32 -040086 set_code_success(regs);
87}
88
89// read configuration word
90static void
91handle_1ab109(struct bregs *regs)
92{
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -050093 regs->cx = pci_config_readw(regs->bx, regs->di);
Kevin O'Connora0dc2962008-03-16 14:29:32 -040094 set_code_success(regs);
95}
96
97// read configuration dword
98static void
99handle_1ab10a(struct bregs *regs)
100{
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -0500101 regs->ecx = pci_config_readl(regs->bx, regs->di);
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400102 set_code_success(regs);
103}
104
105// write configuration byte
106static void
107handle_1ab10b(struct bregs *regs)
108{
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -0500109 pci_config_writeb(regs->bx, regs->di, regs->cl);
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400110 set_code_success(regs);
111}
112
113// write configuration word
114static void
115handle_1ab10c(struct bregs *regs)
116{
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -0500117 pci_config_writew(regs->bx, regs->di, regs->cx);
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400118 set_code_success(regs);
119}
120
121// write configuration dword
122static void
123handle_1ab10d(struct bregs *regs)
124{
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -0500125 pci_config_writel(regs->bx, regs->di, regs->ecx);
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400126 set_code_success(regs);
127}
128
129// get irq routing options
130static void
131handle_1ab10e(struct bregs *regs)
132{
Kevin O'Connor51358db2008-12-28 21:50:29 -0500133 struct pir_header *pirtable_g = (void*)(GET_GLOBAL(PirOffset) + 0);
134 if (! pirtable_g) {
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500135 set_code_invalid(regs, RET_FUNC_NOT_SUPPORTED);
Kevin O'Connor0f803e42008-05-24 23:07:16 -0400136 return;
137 }
138
Kevin O'Connord99908e2009-01-21 19:14:49 -0500139 struct param_s {
140 u16 size;
141 u16 buf_off;
142 u16 buf_seg;
143 } *param_far = (void*)(regs->di+0);
144
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400145 // Validate and update size.
Kevin O'Connord99908e2009-01-21 19:14:49 -0500146 u16 bufsize = GET_FARVAR(regs->es, param_far->size);
147 u16 pirsize = GET_GLOBAL(pirtable_g->size) - sizeof(struct pir_header);
148 SET_FARVAR(regs->es, param_far->size, pirsize);
149 if (bufsize < pirsize) {
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500150 set_code_invalid(regs, RET_BUFFER_TOO_SMALL);
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400151 return;
152 }
153
154 // Get dest buffer.
Kevin O'Connord99908e2009-01-21 19:14:49 -0500155 void *buf_far = (void*)(GET_FARVAR(regs->es, param_far->buf_off)+0);
156 u16 buf_seg = GET_FARVAR(regs->es, param_far->buf_seg);
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400157
158 // Memcpy pir table slots to dest buffer.
Kevin O'Connord99908e2009-01-21 19:14:49 -0500159 memcpy_far(buf_seg, buf_far
Kevin O'Connor871e0a02009-12-30 12:14:53 -0500160 , get_global_seg()
161 , (void*)(pirtable_g->slots) + get_global_offset()
Kevin O'Connor8b267cb2009-01-19 19:25:21 -0500162 , pirsize);
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400163
164 // XXX - bochs bios sets bx to (1 << 9) | (1 << 11)
Kevin O'Connor51358db2008-12-28 21:50:29 -0500165 regs->bx = GET_GLOBAL(pirtable_g->exclusive_irqs);
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400166 set_code_success(regs);
167}
168
169static void
170handle_1ab1XX(struct bregs *regs)
171{
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500172 set_code_unimplemented(regs, RET_FUNC_NOT_SUPPORTED);
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400173}
174
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400175void
176handle_1ab1(struct bregs *regs)
177{
178 //debug_stub(regs);
179
180 if (! CONFIG_PCIBIOS) {
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500181 set_invalid(regs);
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400182 return;
183 }
184
Kevin O'Connora0dc2962008-03-16 14:29:32 -0400185 switch (regs->al) {
186 case 0x01: handle_1ab101(regs); break;
187 case 0x02: handle_1ab102(regs); break;
188 case 0x03: handle_1ab103(regs); break;
189 case 0x08: handle_1ab108(regs); break;
190 case 0x09: handle_1ab109(regs); break;
191 case 0x0a: handle_1ab10a(regs); break;
192 case 0x0b: handle_1ab10b(regs); break;
193 case 0x0c: handle_1ab10c(regs); break;
194 case 0x0d: handle_1ab10d(regs); break;
195 case 0x0e: handle_1ab10e(regs); break;
196 default: handle_1ab1XX(regs); break;
197 }
198}
Kevin O'Connor871e0a02009-12-30 12:14:53 -0500199
200
201/****************************************************************
202 * 32bit interface
203 ****************************************************************/
204
Kevin O'Connor871e0a02009-12-30 12:14:53 -0500205// Entry point for 32bit pci bios functions.
206void VISIBLE32SEG
207handle_pcibios32(struct bregs *regs)
208{
209 debug_enter(regs, DEBUG_HDL_pcibios32);
210 handle_1ab1(regs);
211}
Kevin O'Connor871e0a02009-12-30 12:14:53 -0500212
213struct bios32_s {
214 u32 signature;
215 u32 entry;
216 u8 version;
217 u8 length;
218 u8 checksum;
219 u8 reserved[5];
220} PACKED;
221
222struct bios32_s BIOS32HEADER __aligned(16) VAR16EXPORT = {
223 .signature = 0x5f32335f, // _32_
224 .length = sizeof(BIOS32HEADER) / 16,
225};
226
227void
228bios32_setup(void)
229{
230 dprintf(3, "init bios32\n");
231
232 BIOS32HEADER.entry = (u32)bios32_entry;
233 BIOS32HEADER.checksum -= checksum(&BIOS32HEADER, sizeof(BIOS32HEADER));
234}