piix4: move to module, only load in virtualbox
This commit is contained in:
parent
8ad79b5283
commit
e87f09a1b4
@ -1,5 +1,9 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Only load this in virtualbox for now, as we're not
|
||||
# even sure we're doing the remapping correctly...
|
||||
if lspci -q 80EE:CAFE then insmod /mod/piix4.ko
|
||||
|
||||
# Add module descriptions here...
|
||||
if lspci -q 8086:2415 then insmod /mod/ac97.ko
|
||||
if lspci -q 1234:1111,15ad:07a0 then insmod /mod/vmware.ko
|
||||
|
@ -52,6 +52,7 @@ static size_t _early_log_write(size_t size, uint8_t * buffer) {
|
||||
}
|
||||
|
||||
static void early_log_initialize(void) {
|
||||
outportb(EARLY_LOG_DEVICE + 3, 0x03); /* Disable divisor mode, set parity */
|
||||
printf_output = &_early_log_write;
|
||||
}
|
||||
|
||||
@ -287,9 +288,6 @@ int kmain(struct multiboot * mboot, uint32_t mboot_mag, void* esp) {
|
||||
/* Set up preempt source */
|
||||
pit_initialize();
|
||||
|
||||
/* Handle PIRQ remapping if necessary */
|
||||
pci_remap();
|
||||
|
||||
/* Install generic PC device drivers. */
|
||||
ps2hid_install();
|
||||
serial_initialize();
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <stdint.h>
|
||||
#include <kernel/string.h>
|
||||
#include <kernel/pci.h>
|
||||
#include <kernel/printf.h>
|
||||
|
||||
/* TODO: PCI is sufficiently generic this shouldn't depend
|
||||
* directly on x86-64 hardware... */
|
||||
@ -126,51 +127,6 @@ void pci_scan(pci_func_t f, int type, void * extra) {
|
||||
}
|
||||
}
|
||||
|
||||
static void find_isa_bridge(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) {
|
||||
if (vendorid == 0x8086 && (deviceid == 0x7000 || deviceid == 0x7110)) {
|
||||
*((uint32_t *)extra) = device;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint32_t pci_isa = 0;
|
||||
static uint8_t pci_remaps[4] = {0};
|
||||
|
||||
/**
|
||||
* PIIX4 PIRQ routing control.
|
||||
* Maps interrupt pins to correct interrupts.
|
||||
*/
|
||||
#define PIIX4_PCI_PIRQRC 0x60
|
||||
void pci_remap(void) {
|
||||
pci_scan(&find_isa_bridge, -1, &pci_isa);
|
||||
if (pci_isa) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
pci_remaps[i] = pci_read_field(pci_isa, PIIX4_PCI_PIRQRC + i, 1);
|
||||
|
||||
/* If this PIRQ is not assigned, assign it. */
|
||||
if (pci_remaps[i] == 0x80) {
|
||||
pci_remaps[i] = 10 + i%1;
|
||||
}
|
||||
}
|
||||
uint32_t out = 0;
|
||||
memcpy(&out, &pci_remaps, 4);
|
||||
pci_write_field(pci_isa, PIIX4_PCI_PIRQRC, 4, out);
|
||||
}
|
||||
}
|
||||
|
||||
int pci_get_interrupt(uint32_t device) {
|
||||
if (pci_isa) {
|
||||
uint32_t irq_pin = pci_read_field(device, PCI_INTERRUPT_PIN, 1);
|
||||
/* If there is no irq pin, hope the line is set correctly... */
|
||||
if (irq_pin == 0) {
|
||||
return pci_read_field(device, PCI_INTERRUPT_LINE, 1);
|
||||
}
|
||||
/* Calculate PIRQ from pin and device slot. */
|
||||
int pirq = (irq_pin + pci_extract_slot(device) - 2) % 4;
|
||||
/* We don't actually have to rewrite this, but it's nice of us. */
|
||||
pci_write_field(device, PCI_INTERRUPT_LINE, 1, pci_remaps[pirq]);
|
||||
return pci_remaps[pirq];
|
||||
} else {
|
||||
return pci_read_field(device, PCI_INTERRUPT_LINE, 1);
|
||||
}
|
||||
return pci_read_field(device, PCI_INTERRUPT_LINE, 1);
|
||||
}
|
||||
|
80
modules/piix4.c
Normal file
80
modules/piix4.c
Normal file
@ -0,0 +1,80 @@
|
||||
/**
|
||||
* @file modules/piix4.c
|
||||
* @brief Intel PIIX4 ISA Bridge Driver
|
||||
*
|
||||
* @copyright
|
||||
* This file is part of ToaruOS and is released under the terms
|
||||
* of the NCSA / University of Illinois License - see LICENSE.md
|
||||
* Copyright (C) 2021 K. Lange
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <kernel/types.h>
|
||||
#include <kernel/args.h>
|
||||
#include <kernel/printf.h>
|
||||
#include <kernel/pci.h>
|
||||
#include <kernel/module.h>
|
||||
|
||||
#define PIIX4_PCI_PIRQRC 0x60
|
||||
|
||||
static void find_isa_bridge(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) {
|
||||
if (vendorid == 0x8086 && (deviceid == 0x7000 || deviceid == 0x7110)) {
|
||||
*((uint32_t *)extra) = device;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t pci_isa = 0;
|
||||
static int pci_isa_base_slot = 0;
|
||||
static int pci_isa_bus_offset = 0;
|
||||
static int pci_isa_last_bus = 0;
|
||||
static uint8_t pci_remaps[4] = {0};
|
||||
|
||||
static void piix_remap(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) {
|
||||
uint32_t irq_pin = pci_read_field(device, PCI_INTERRUPT_PIN, 1);
|
||||
uint32_t irq_line = pci_read_field(device, PCI_INTERRUPT_LINE, 1);
|
||||
if (irq_pin == 0) return;
|
||||
if (pci_extract_bus(device) != pci_isa_last_bus) {
|
||||
pci_isa_bus_offset++;
|
||||
pci_isa_last_bus = pci_extract_bus(device);
|
||||
}
|
||||
/* Calculate PIRQ from pin and device slot. */
|
||||
int slot = (pci_extract_slot(device) - pci_isa_base_slot) % 4;
|
||||
int bus = (pci_isa_bus_offset) % 4;
|
||||
int pirq = (slot + irq_pin + bus - 1) % 4;
|
||||
if (irq_line < 32 && irq_line != pci_remaps[pirq]) {
|
||||
pci_write_field(device, PCI_INTERRUPT_LINE, 1, pci_remaps[pirq]);
|
||||
}
|
||||
}
|
||||
|
||||
static int init(int argc, char * argv[]) {
|
||||
if (args_present("nopciremap")) return -ENODEV;
|
||||
|
||||
pci_scan(&find_isa_bridge, -1, &pci_isa);
|
||||
if (!pci_isa) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pci_isa_base_slot = pci_extract_slot(pci_isa);
|
||||
pci_isa_last_bus = pci_extract_bus(pci_isa);
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
pci_remaps[i] = pci_read_field(pci_isa, PIIX4_PCI_PIRQRC + i, 1);
|
||||
}
|
||||
|
||||
uint32_t out = 0;
|
||||
memcpy(&out, &pci_remaps, 4);
|
||||
pci_write_field(pci_isa, PIIX4_PCI_PIRQRC, 4, out);
|
||||
pci_scan(piix_remap, -1, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fini(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct Module metadata = {
|
||||
.name = "piix4",
|
||||
.init = init,
|
||||
.fini = fini,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user