[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:
28
dev/driver.c
28
dev/driver.c
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ else
|
||||
QEMU="qemu-system-i386"
|
||||
PROJECT="pc-x86-test"
|
||||
CPU=qemu32
|
||||
MACHINE=q35
|
||||
MACHINE=pc
|
||||
fi
|
||||
|
||||
if (( $DO_LEGACY )); then
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user