blob: 8e3a51e45086f64f0c330a3a5a6db73b86e56c67 [file] [log] [blame]
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2001 Ronald G. Minnich
5 * Copyright (C) 2005 Nick.Barker9@btinternet.com
6 * Copyright (C) 2007-2009 coresystems GmbH
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000016 */
17
Edward O'Callaghan91810dd2014-07-30 13:53:04 +100018#include <arch/registers.h>
19#include <console/console.h>
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000020#include <device/pci.h>
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000021#include <device/pci_ops.h>
22#include <string.h>
Edward O'Callaghan91810dd2014-07-30 13:53:04 +100023
Patrick Georgi199b09c2012-11-22 12:46:12 +010024/* we use x86emu's register file representation */
25#include <x86emu/regs.h>
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000026
Edward O'Callaghan91810dd2014-07-30 13:53:04 +100027#include "x86.h"
28
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000029// errors go in AH. Just set these up so that word assigns
30// will work. KISS.
31enum {
Mark Marshalld08e69d2009-11-05 09:03:04 +000032 PCIBIOS_SUCCESSFUL = 0x0000,
33 PCIBIOS_UNSUPPORTED = 0x8100,
34 PCIBIOS_BADVENDOR = 0x8300,
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000035 PCIBIOS_NODEV = 0x8600,
36 PCIBIOS_BADREG = 0x8700
37};
38
Patrick Georgi199b09c2012-11-22 12:46:12 +010039int int10_handler(void)
Stefan Reinauer216fa462011-10-12 14:25:07 -070040{
Patrick Georgi503af722012-11-22 10:48:18 +010041 int res=0;
Stefan Reinauer216fa462011-10-12 14:25:07 -070042 static u8 cursor_row=0, cursor_col=0;
Patrick Georgi199b09c2012-11-22 12:46:12 +010043 switch((X86_EAX & 0xff00)>>8) {
Stefan Reinauer216fa462011-10-12 14:25:07 -070044 case 0x01: // Set cursor shape
Patrick Georgi503af722012-11-22 10:48:18 +010045 res = 1;
Stefan Reinauer216fa462011-10-12 14:25:07 -070046 break;
47 case 0x02: // Set cursor position
Patrick Georgi199b09c2012-11-22 12:46:12 +010048 if (cursor_row != ((X86_EDX >> 8) & 0xff) ||
49 cursor_col >= (X86_EDX & 0xff)) {
Stefan Reinauer216fa462011-10-12 14:25:07 -070050 printk(BIOS_INFO, "\n");
51 }
Patrick Georgi199b09c2012-11-22 12:46:12 +010052 cursor_row = (X86_EDX >> 8) & 0xff;
53 cursor_col = X86_EDX & 0xff;
Patrick Georgi503af722012-11-22 10:48:18 +010054 res = 1;
Stefan Reinauer216fa462011-10-12 14:25:07 -070055 break;
56 case 0x03: // Get cursor position
Patrick Georgi199b09c2012-11-22 12:46:12 +010057 X86_EAX &= 0x00ff;
58 X86_ECX = 0x0607;
59 X86_EDX = (cursor_row << 8) | cursor_col;
Patrick Georgi503af722012-11-22 10:48:18 +010060 res = 1;
Stefan Reinauer216fa462011-10-12 14:25:07 -070061 break;
62 case 0x06: // Scroll up
63 printk(BIOS_INFO, "\n");
Patrick Georgi503af722012-11-22 10:48:18 +010064 res = 1;
Stefan Reinauer216fa462011-10-12 14:25:07 -070065 break;
66 case 0x08: // Get Character and Mode at Cursor Position
Patrick Georgi199b09c2012-11-22 12:46:12 +010067 X86_EAX = 0x0f00 | 'A'; // White on black 'A'
Patrick Georgi503af722012-11-22 10:48:18 +010068 res = 1;
Stefan Reinauer216fa462011-10-12 14:25:07 -070069 break;
70 case 0x09: // Write Character and attribute
Stefan Reinauer20d9de32011-12-13 23:08:03 +010071 case 0x0e: // Write Character
Patrick Georgi199b09c2012-11-22 12:46:12 +010072 printk(BIOS_INFO, "%c", X86_EAX & 0xff);
Patrick Georgi503af722012-11-22 10:48:18 +010073 res = 1;
Stefan Reinauer216fa462011-10-12 14:25:07 -070074 break;
75 case 0x0f: // Get video mode
Patrick Georgi199b09c2012-11-22 12:46:12 +010076 X86_EAX = 0x5002; //80x25
77 X86_EBX &= 0x00ff;
Patrick Georgi503af722012-11-22 10:48:18 +010078 res = 1;
Stefan Reinauer216fa462011-10-12 14:25:07 -070079 break;
80 default:
81 printk(BIOS_WARNING, "Unknown INT10 function %04x!\n",
Patrick Georgi199b09c2012-11-22 12:46:12 +010082 X86_EAX & 0xffff);
Stefan Reinauer216fa462011-10-12 14:25:07 -070083 break;
84 }
85 return res;
86}
Maciej Pijankaea921852009-10-27 14:29:29 +000087
Patrick Georgi199b09c2012-11-22 12:46:12 +010088int int12_handler(void)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000089{
Patrick Georgi199b09c2012-11-22 12:46:12 +010090 X86_EAX = 64 * 1024;
Patrick Georgi503af722012-11-22 10:48:18 +010091 return 1;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000092}
93
Patrick Georgi199b09c2012-11-22 12:46:12 +010094int int16_handler(void)
Stefan Reinauer216fa462011-10-12 14:25:07 -070095{
Patrick Georgi503af722012-11-22 10:48:18 +010096 int res=0;
Patrick Georgi199b09c2012-11-22 12:46:12 +010097 switch((X86_EAX & 0xff00)>>8) {
Stefan Reinauer216fa462011-10-12 14:25:07 -070098 case 0x00: // Check for Keystroke
Patrick Georgi199b09c2012-11-22 12:46:12 +010099 X86_EAX = 0x6120; // Space Bar, Space
Patrick Georgi503af722012-11-22 10:48:18 +0100100 res = 1;
Stefan Reinauer216fa462011-10-12 14:25:07 -0700101 break;
102 case 0x01: // Check for Keystroke
Patrick Georgi199b09c2012-11-22 12:46:12 +0100103 X86_EFLAGS |= 1<<6; // Zero Flag set (no key available)
Patrick Georgi503af722012-11-22 10:48:18 +0100104 res = 1;
Stefan Reinauer216fa462011-10-12 14:25:07 -0700105 break;
106 default:
107 printk(BIOS_WARNING, "Unknown INT16 function %04x!\n",
Patrick Georgi199b09c2012-11-22 12:46:12 +0100108 X86_EAX & 0xffff);
Stefan Reinauer216fa462011-10-12 14:25:07 -0700109 break;
110 }
111 return res;
112}
113
Stefan Reinauer607cdf62010-04-26 12:08:51 +0000114#define PCI_CONFIG_SPACE_TYPE1 (1 << 0)
Stefan Reinauer607cdf62010-04-26 12:08:51 +0000115#define PCI_SPECIAL_CYCLE_TYPE1 (1 << 4)
Stefan Reinauer607cdf62010-04-26 12:08:51 +0000116
Patrick Georgi199b09c2012-11-22 12:46:12 +0100117int int1a_handler(void)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000118{
Patrick Georgi199b09c2012-11-22 12:46:12 +0100119 unsigned short func = (unsigned short)X86_EAX;
Patrick Georgi503af722012-11-22 10:48:18 +0100120 int retval = 1;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000121 unsigned short devid, vendorid, devfn;
Martin Roth63373ed2013-07-08 16:24:19 -0600122 /* Use short to get rid of garbage in upper half of 32-bit register */
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000123 short devindex;
124 unsigned char bus;
125 struct device *dev;
Stefan Reinauer46634e72009-11-05 12:44:50 +0000126 u32 dword;
127 u16 word;
128 u8 byte, reg;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000129
Mark Marshalld08e69d2009-11-05 09:03:04 +0000130 switch (func) {
Stefan Reinauer216fa462011-10-12 14:25:07 -0700131 case 0xb101: /* PCIBIOS Check */
Patrick Georgi199b09c2012-11-22 12:46:12 +0100132 X86_EDX = 0x20494350; /* ' ICP' */
133 X86_EAX &= 0xffff0000; /* Clear AH / AL */
134 X86_EAX |= PCI_CONFIG_SPACE_TYPE1 | PCI_SPECIAL_CYCLE_TYPE1;
Stefan Reinauer607cdf62010-04-26 12:08:51 +0000135 // last bus in the system. Hard code to 255 for now.
Martin Roth63373ed2013-07-08 16:24:19 -0600136 // dev_enumerate() does not seem to tell us (publicly)
Patrick Georgi199b09c2012-11-22 12:46:12 +0100137 X86_ECX = 0xff;
138 X86_EDI = 0x00000000; /* protected mode entry */
Patrick Georgi503af722012-11-22 10:48:18 +0100139 retval = 1;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000140 break;
Stefan Reinauer216fa462011-10-12 14:25:07 -0700141 case 0xb102: /* Find Device */
Patrick Georgi199b09c2012-11-22 12:46:12 +0100142 devid = X86_ECX;
143 vendorid = X86_EDX;
144 devindex = X86_ESI;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000145 dev = 0;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000146 while ((dev = dev_find_device(vendorid, devid, dev))) {
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000147 if (devindex <= 0)
148 break;
149 devindex--;
150 }
151 if (dev) {
152 unsigned short busdevfn;
Patrick Georgi199b09c2012-11-22 12:46:12 +0100153 X86_EAX &= 0xffff00ff; /* Clear AH */
154 X86_EAX |= PCIBIOS_SUCCESSFUL;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000155 // busnum is an unsigned char;
156 // devfn is an int, so we mask it off.
157 busdevfn = (dev->bus->secondary << 8)
Mark Marshalld08e69d2009-11-05 09:03:04 +0000158 | (dev->path.pci.devfn & 0xff);
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000159 printk(BIOS_DEBUG, "0x%x: return 0x%x\n", func, busdevfn);
Patrick Georgi199b09c2012-11-22 12:46:12 +0100160 X86_EBX = busdevfn;
Patrick Georgi503af722012-11-22 10:48:18 +0100161 retval = 1;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000162 } else {
Patrick Georgi199b09c2012-11-22 12:46:12 +0100163 X86_EAX &= 0xffff00ff; /* Clear AH */
164 X86_EAX |= PCIBIOS_NODEV;
Patrick Georgi503af722012-11-22 10:48:18 +0100165 retval = 0;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000166 }
Mark Marshalld08e69d2009-11-05 09:03:04 +0000167 break;
Stefan Reinauer216fa462011-10-12 14:25:07 -0700168 case 0xb10a: /* Read Config Dword */
169 case 0xb109: /* Read Config Word */
170 case 0xb108: /* Read Config Byte */
171 case 0xb10d: /* Write Config Dword */
172 case 0xb10c: /* Write Config Word */
173 case 0xb10b: /* Write Config Byte */
Patrick Georgi199b09c2012-11-22 12:46:12 +0100174 devfn = X86_EBX & 0xff;
175 bus = X86_EBX >> 8;
176 reg = X86_EDI;
Kyösti Mälkki98d19572019-07-04 13:15:01 +0300177 dev = pcidev_path_on_bus(bus, devfn);
Mark Marshalld08e69d2009-11-05 09:03:04 +0000178 if (!dev) {
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000179 printk(BIOS_DEBUG, "0x%x: BAD DEVICE bus %d devfn 0x%x\n", func, bus, devfn);
Stefan Reinauer607cdf62010-04-26 12:08:51 +0000180 // Or are we supposed to return PCIBIOS_NODEV?
Patrick Georgi199b09c2012-11-22 12:46:12 +0100181 X86_EAX &= 0xffff00ff; /* Clear AH */
182 X86_EAX |= PCIBIOS_BADREG;
Patrick Georgi503af722012-11-22 10:48:18 +0100183 retval = 0;
Mark Marshalld08e69d2009-11-05 09:03:04 +0000184 return retval;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000185 }
Mark Marshalld08e69d2009-11-05 09:03:04 +0000186 switch (func) {
Stefan Reinauer216fa462011-10-12 14:25:07 -0700187 case 0xb108: /* Read Config Byte */
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000188 byte = pci_read_config8(dev, reg);
Patrick Georgi199b09c2012-11-22 12:46:12 +0100189 X86_ECX = byte;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000190 break;
Stefan Reinauer216fa462011-10-12 14:25:07 -0700191 case 0xb109: /* Read Config Word */
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000192 word = pci_read_config16(dev, reg);
Patrick Georgi199b09c2012-11-22 12:46:12 +0100193 X86_ECX = word;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000194 break;
Stefan Reinauer216fa462011-10-12 14:25:07 -0700195 case 0xb10a: /* Read Config Dword */
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000196 dword = pci_read_config32(dev, reg);
Patrick Georgi199b09c2012-11-22 12:46:12 +0100197 X86_ECX = dword;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000198 break;
Stefan Reinauer216fa462011-10-12 14:25:07 -0700199 case 0xb10b: /* Write Config Byte */
Patrick Georgi199b09c2012-11-22 12:46:12 +0100200 byte = X86_ECX;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000201 pci_write_config8(dev, reg, byte);
202 break;
Stefan Reinauer216fa462011-10-12 14:25:07 -0700203 case 0xb10c: /* Write Config Word */
Patrick Georgi199b09c2012-11-22 12:46:12 +0100204 word = X86_ECX;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000205 pci_write_config16(dev, reg, word);
206 break;
Stefan Reinauer216fa462011-10-12 14:25:07 -0700207 case 0xb10d: /* Write Config Dword */
Patrick Georgi199b09c2012-11-22 12:46:12 +0100208 dword = X86_ECX;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000209 pci_write_config32(dev, reg, dword);
210 break;
211 }
212
Julius Wernercd49cce2019-03-05 16:53:33 -0800213#if CONFIG(REALMODE_DEBUG)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000214 printk(BIOS_DEBUG, "0x%x: bus %d devfn 0x%x reg 0x%x val 0x%x\n",
Patrick Georgi199b09c2012-11-22 12:46:12 +0100215 func, bus, devfn, reg, X86_ECX);
Myles Watson6c9bc012010-09-07 22:30:15 +0000216#endif
Patrick Georgi199b09c2012-11-22 12:46:12 +0100217 X86_EAX &= 0xffff00ff; /* Clear AH */
218 X86_EAX |= PCIBIOS_SUCCESSFUL;
Patrick Georgi503af722012-11-22 10:48:18 +0100219 retval = 1;
Mark Marshalld08e69d2009-11-05 09:03:04 +0000220 break;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000221 default:
Mark Marshalld08e69d2009-11-05 09:03:04 +0000222 printk(BIOS_ERR, "UNSUPPORTED PCIBIOS FUNCTION 0x%x\n", func);
Patrick Georgi199b09c2012-11-22 12:46:12 +0100223 X86_EAX &= 0xffff00ff; /* Clear AH */
224 X86_EAX |= PCIBIOS_UNSUPPORTED;
Patrick Georgi503af722012-11-22 10:48:18 +0100225 retval = 0;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000226 break;
227 }
228
229 return retval;
230}