[platform][pc] fix up bios32 PCI support, get pci IDE working again

-Spiff up the device driver starting logic to allow for statically
started devices, instead of always automatic.
This commit is contained in:
Travis Geiselbrecht
2018-12-31 16:47:32 -08:00
parent 1fbb67228d
commit 4c29a608e9
10 changed files with 166 additions and 118 deletions

View File

@@ -26,6 +26,7 @@
#include <err.h>
#include <trace.h>
/* static list of devices constructed with DEVICE_INSTANCE macros */
extern struct device __devices[];
extern struct device __devices_end[];
@@ -35,14 +36,15 @@ status_t device_init_all(void)
struct device *dev = __devices;
while (dev != __devices_end) {
dprintf(INFO, "dev: initializing device %s:%s\n", dev->driver->type, dev->name);
status_t code = device_init(dev);
if (dev->flags & DEVICE_FLAG_AUTOINIT) {
status_t code = device_init(dev);
if (code < 0) {
TRACEF("Driver init failed for driver \"%s\", device \"%s\", reason %d\n",
dev->driver->type, dev->name, code);
if (code < 0) {
TRACEF("Driver init failed for driver \"%s\", device \"%s\", reason %d\n",
dev->driver->type, dev->name, code);
res = code;
res = code;
}
}
dev++;
@@ -81,10 +83,18 @@ status_t device_init(struct device *dev)
const struct driver_ops *ops = dev->driver->ops;
if (ops && ops->init)
return ops->init(dev);
else
if (ops && ops->init) {
dprintf(INFO, "dev: initializing device %s:%s\n", dev->driver->type, dev->name);
status_t err = ops->init(dev);
if (err < 0) {
dev->device_state = DEVICE_INITIALIZED_FAILED;
} else {
dev->device_state = DEVICE_INITIALIZED;
}
return err;
} else {
return ERR_NOT_SUPPORTED;
}
}
status_t device_fini(struct device *dev)

View File

@@ -624,7 +624,7 @@ static const struct platform_pcnet_config pcnet0_config = {
.index = 0,
};
DEVICE_INSTANCE(netif, pcnet0, &pcnet0_config);
DEVICE_INSTANCE(netif, pcnet0, &pcnet0_config, 0);
static void pcnet_init_hook(uint level)
{

View File

@@ -27,6 +27,8 @@
#include <list.h> // for containerof
#include <compiler.h>
__BEGIN_CDECLS
struct driver;
/*
@@ -37,6 +39,8 @@ struct device {
const char *name;
const struct driver *driver;
uint32_t flags;
/* instance specific config data populated at instantiation */
const void *config;
@@ -44,8 +48,16 @@ struct device {
void *state;
// TODO: add generic state, such as suspend/resume state, etc...
enum {
DEVICE_UNINITIALIZED,
DEVICE_INITIALIZED,
DEVICE_INITIALIZED_FAILED,
} device_state;
};
/* set this flag to auto initialize the device when device_init_all is called */
#define DEVICE_FLAG_AUTOINIT 0x1
/* device class, mainly used as a unique magic pointer to validate ops */
struct device_class {
const char *name;
@@ -79,13 +91,16 @@ struct driver {
.ops = ops_, \
}
#define DEVICE_INSTANCE(type_, name_, config_) \
#define DEVICE_INSTANCE(type_, name_, config_, flags_) \
extern struct driver concat(__driver_, type_); \
struct device concat(__device_, concat(type_, concat(_, name_))) \
__ALIGNED(sizeof(void *)) __SECTION(".devices") = { \
.name = #name_, \
.driver = &concat(__driver_, type_), \
.flags = flags_, \
.config = config_, \
.state = NULL, \
.device_state = DEVICE_UNINITIALIZED, \
}
/*
@@ -104,7 +119,9 @@ struct driver {
&concat(__device_, concat(type_, concat(_, name_))); \
})
/* initialize all static devices with AUTOINIT flag set */
status_t device_init_all(void);
status_t device_fini_all(void);
status_t device_init(struct device *dev);
@@ -113,5 +130,7 @@ status_t device_fini(struct device *dev);
status_t device_suspend(struct device *dev);
status_t device_resume(struct device *dev);
__END_CDECLS
#endif

View File

@@ -236,18 +236,18 @@ static status_t ide_init(struct device *dev)
}
// attempt pci detection
if (config->legacy_index < 0) {
if (config->legacy_index == 0x80 || config->legacy_index == 0x81) {
pci_location_t loc;
pci_config_t pci_config;
err = pci_find_pci_class_code(&loc, 0x010180, 0);
if (err != _PCI_SUCCESSFUL) {
LTRACEF("Failed to find IDE device\n");
LTRACEF("Failed to find PCI IDE device\n");
res = ERR_NOT_FOUND;
goto err;
}
LTRACEF("Found IDE device at %02x:%02x\n", loc.bus, loc.dev_fn);
LTRACEF("Found PCI IDE device at %02x:%02x\n", loc.bus, loc.dev_fn);
for (i=0; i < sizeof(pci_config) / sizeof(uint32_t); i++) {
uint32_t reg = sizeof(uint32_t) * i;
@@ -265,11 +265,9 @@ static status_t ide_init(struct device *dev)
}
// TODO: fill this in from the bars
//state->irq = ide_device_irqs[0];
//state->regs = ide_device_regs[0];
//state->type[0] = state->type[1] = TYPE_NONE;
res = ERR_NOT_CONFIGURED;
goto err;
state->irq = ide_device_irqs[config->legacy_index & 0x7f];
state->regs = ide_device_regs[config->legacy_index & 0x7f];
state->type[0] = state->type[1] = TYPE_NONE;
} else {
// legacy isa
DEBUG_ASSERT(config->legacy_index < 2);

View File

@@ -25,7 +25,7 @@
#define __PLATFORM_IDE_H
struct platform_ide_config {
int legacy_index; // -1 for pci detection, 0 or 1 for legacy ISA IDE
int legacy_index; // 0x80, 0x81 for pci detection channel 0 and 1, 0 or 1 for legacy ISA IDE
};
#endif

View File

@@ -28,6 +28,9 @@
#include <kernel/spinlock.h>
#include <arch/x86/descriptor.h>
#include <dev/pci.h>
#include <trace.h>
#define LOCAL_TRACE 0
static int last_bus = 0;
static spin_lock_t lock;
@@ -234,8 +237,8 @@ int pci_set_irq_hw_int(const pci_location_t *state, uint8_t int_pin, uint8_t irq
void pci_init(void)
{
if (!pci_bios_detect()) {
dprintf(INFO, "pci bios functions installed\n");
dprintf(INFO, "last pci bus is %d\n", last_bus);
dprintf(INFO, "PCI: pci bios functions installed\n");
dprintf(INFO, "PCI: last pci bus is %d\n", last_bus);
}
}
@@ -539,95 +542,96 @@ static int bios_set_irq_hw_int(const pci_location_t *state, uint8_t int_pin, uin
static const char *pci_signature = "PCI ";
static int pci_bios_detect(void)
{
// disable for now, pci bios32 doesn't work without a temporary identity map
// set up on the mmu
return 0;
#if !ARCH_X86_32
// disable for x86-64 because of bios32
return ERR_NOT_SUPPORTED;
#endif
pci_bios_info *pci = find_pci_bios_info();
if (pci != NULL) {
printf("Found PCI structure at %p\n", pci);
printf("\nPCI header info:\n");
printf("%c%c%c%c\n", pci->magic[0], pci->magic[1], pci->magic[2],
pci->magic[3]);
printf("%p\n", pci->entry);
printf("%d\n", pci->length * 16);
printf("%d\n", pci->checksum);
uint32_t adr, temp, len;
uint8_t err;
bios32_entry.offset = (uint32_t)(uintptr_t)pci->entry + KERNEL_BASE;
bios32_entry.selector = CODE_SELECTOR;
__asm__(
"lcall *(%%edi)"
: "=a"(err), /* AL out=status */
"=b"(adr), /* EBX out=code segment base adr */
"=c"(len), /* ECX out=code segment size */
"=d"(temp) /* EDX out=entry pt offset in code */
: "0"(0x49435024),/* EAX in=service="$PCI" */
"1"(0), /* EBX in=0=get service entry pt */
"D"(&bios32_entry)
);
if (err == 0x80) {
dprintf(INFO, "BIOS32 found, but no PCI BIOS\n");
return -1;
}
if (err != 0) {
dprintf(INFO, "BIOS32 call to locate PCI BIOS returned %x\n", err);
return -1;
}
bios32_entry.offset = adr + temp;
// now call PCI_BIOS_PRESENT to get version, hw mechanism, and last bus
uint16_t present, version, busses;
uint32_t signature;
__asm__(
"lcall *(%%edi) \n\t"
"jc 1f \n\t"
"xor %%ah,%%ah \n"
"1:"
: "=a"(present),
"=b"(version),
"=c"(busses),
"=d"(signature)
: "0"(PCIBIOS_PRESENT),
"D"(&bios32_entry)
);
if (present & 0xff00) {
dprintf(INFO, "PCI_BIOS_PRESENT call returned ah=%02x\n", present >> 8);
return -1;
}
if (signature != *(uint32_t *)pci_signature) {
dprintf(INFO, "PCI_BIOS_PRESENT call returned edx=%08x\n", signature);
return -1;
}
//dprintf(DEBUG, "busses=%04x\n", busses);
last_bus = busses & 0xff;
g_pci_find_pci_device = bios_find_pci_device;
g_pci_find_pci_class_code = bios_find_pci_class_code;
g_pci_read_config_word = bios_read_config_word;
g_pci_read_config_half = bios_read_config_half;
g_pci_read_config_byte = bios_read_config_byte;
g_pci_write_config_word = bios_write_config_word;
g_pci_write_config_half = bios_write_config_half;
g_pci_write_config_byte = bios_write_config_byte;
g_pci_get_irq_routing_options = bios_get_irq_routing_options;
g_pci_set_irq_hw_int = bios_set_irq_hw_int;
return 0;
if (!pci) {
return ERR_NOT_CONFIGURED;
}
return -1;
dprintf(INFO, "PCI: found BIOS32 structure at %p\n", pci);
LTRACEF("BIOS32 header info:\n");
LTRACEF("magic '%c%c%c%c' entry %p len %d checksum %#hhx\n",
pci->magic[0], pci->magic[1], pci->magic[2], pci->magic[3],
pci->entry, pci->length * 16, pci->checksum);
uint32_t adr, temp, len;
uint8_t err;
bios32_entry.offset = (uint32_t)(uintptr_t)pci->entry + KERNEL_BASE;
bios32_entry.selector = CODE_SELECTOR;
__asm__(
"lcall *(%%edi)"
: "=a"(err), /* AL out=status */
"=b"(adr), /* EBX out=code segment base adr */
"=c"(len), /* ECX out=code segment size */
"=d"(temp) /* EDX out=entry pt offset in code */
: "0"(0x49435024),/* EAX in=service="$PCI" */
"1"(0), /* EBX in=0=get service entry pt */
"D"(&bios32_entry)
);
if (err == 0x80) {
dprintf(INFO, "BIOS32 found, but no PCI BIOS\n");
return ERR_NOT_CONFIGURED;
}
if (err != 0) {
dprintf(INFO, "BIOS32 call to locate PCI BIOS returned %x\n", err);
return ERR_NOT_CONFIGURED;
}
LTRACEF("BIOS32 entry segment base %#x offset %#x\n", adr, temp);
bios32_entry.offset = adr + temp + KERNEL_BASE;
// now call PCI_BIOS_PRESENT to get version, hw mechanism, and last bus
uint16_t present, version, busses;
uint32_t signature;
__asm__(
"lcall *(%%edi) \n\t"
"jc 1f \n\t"
"xor %%ah,%%ah \n"
"1:"
: "=a"(present),
"=b"(version),
"=c"(busses),
"=d"(signature)
: "0"(PCIBIOS_PRESENT),
"D"(&bios32_entry)
);
LTRACEF("PCI_BIOS_PRESENT returns present %#x\n", present);
if (present & 0xff00) {
dprintf(INFO, "PCI_BIOS_PRESENT call returned ah=%#02x\n", present >> 8);
return ERR_NOT_CONFIGURED;
}
if (signature != *(uint32_t *)pci_signature) {
dprintf(INFO, "PCI_BIOS_PRESENT call returned edx=%#08x\n", signature);
return ERR_NOT_CONFIGURED;
}
last_bus = busses & 0xff;
g_pci_find_pci_device = bios_find_pci_device;
g_pci_find_pci_class_code = bios_find_pci_class_code;
g_pci_read_config_word = bios_read_config_word;
g_pci_read_config_half = bios_read_config_half;
g_pci_read_config_byte = bios_read_config_byte;
g_pci_write_config_word = bios_write_config_word;
g_pci_write_config_half = bios_write_config_half;
g_pci_write_config_byte = bios_write_config_byte;
g_pci_get_irq_routing_options = bios_get_irq_routing_options;
g_pci_set_irq_hw_int = bios_set_irq_hw_int;
return NO_ERROR;
}

View File

@@ -252,9 +252,8 @@ void platform_init(void)
platform_init_debug();
platform_init_keyboard(&console_input_buf);
#if defined(ARCH_X86)
pci_init();
#endif
platform_init_mmu_mappings();
}

View File

@@ -8,7 +8,7 @@ CPU ?= generic
MODULE_DEPS += \
lib/bio \
lib/cbuf \
lib/cbuf
MODULE_SRCS += \
$(LOCAL_DIR)/interrupts.c \
@@ -23,5 +23,7 @@ MODULE_SRCS += \
LK_HEAP_IMPLEMENTATION ?= dlmalloc
MODULE_DEPS += app/pcitests
include make/module.mk

View File

@@ -54,7 +54,7 @@ else
QEMU="qemu-system-i386"
PROJECT="pc-x86-test"
CPU=qemu32
MACHINE=q35
MACHINE=pc
fi
if (( $DO_LEGACY )); then

View File

@@ -44,23 +44,39 @@ static const struct platform_uart_config uart0_config = {
DEVICE_INSTANCE(uart, uart0, &uart0_config);
#endif
#ifndef ARCH_X86_64
// two legacy ISA IDE devices
static const struct platform_ide_config ide0_config = {
.legacy_index = 0,
};
DEVICE_INSTANCE(ide, ide0, &ide0_config);
DEVICE_INSTANCE(ide, ide0, &ide0_config, 0);
static const struct platform_ide_config ide1_config = {
.legacy_index = 1,
};
DEVICE_INSTANCE(ide, ide1, &ide1_config, 0);
DEVICE_INSTANCE(ide, ide1, &ide1_config);
// two PCI IDE devices
static const struct platform_ide_config pci_ide0_config = {
.legacy_index = 0x80,
};
DEVICE_INSTANCE(ide, pci_ide0, &pci_ide0_config, 0);
#endif
static const struct platform_ide_config pci_ide1_config = {
.legacy_index = 0x81,
};
DEVICE_INSTANCE(ide, pci_ide1, &pci_ide1_config, 0);
void target_init(void)
{
// initialize static devices
device_init_all();
// try to initialize pci ide first
if (device_init(&__device_ide_pci_ide0) < 0 || device_init(&__device_ide_pci_ide1) < 0) {
// if that fails, initialize the legacy ISA IDE controllers
device_init(&__device_ide_ide0);
device_init(&__device_ide_ide1);
}
}