Some sort of PCI subsystem, maybe
This commit is contained in:
parent
5c549e1068
commit
ebe1c24dbd
@ -189,6 +189,8 @@ ToAruOS contains a number of third-party packages under various licenses. Those
|
||||
|
||||
* The Curses sample applications provided in `userspace/extra/curses` are by Pradeep Padala. A readme containing a license is provided [in that directory](../userspace/extra/curses/README.md).
|
||||
|
||||
* A list of PCI vendor and device names, from [the PCI Database](http://pcidatabase.com), is included in `kernel/include/pci_list.h`.
|
||||
|
||||
* Build scripts will also retrieve copies of the following software and patches to them:
|
||||
* [GCC](http://gcc.gnu.org/)
|
||||
* [Newlib](http://sourceware.org/newlib/)
|
||||
|
@ -4,44 +4,103 @@
|
||||
*/
|
||||
|
||||
#include <system.h>
|
||||
#include <pci.h>
|
||||
#include <pci_list.h>
|
||||
|
||||
#define PCI_CONFIG_ADDRESS 0xCF8
|
||||
#define PCI_CONFIG_DATA 0xCFC
|
||||
|
||||
void pci_install(void) {
|
||||
/* Do nothing */
|
||||
|
||||
uint32_t pci_read_field(uint32_t device, int field, int size) {
|
||||
outportl(PCI_ADDRESS_PORT, pci_get_addr(device, field));
|
||||
|
||||
if (size == 4) {
|
||||
uint32_t t = inportl(PCI_VALUE_PORT);
|
||||
return t;
|
||||
} else if (size == 2) {
|
||||
uint16_t t = inports(PCI_VALUE_PORT + (field & 2));
|
||||
return t;
|
||||
} else if (size == 1) {
|
||||
uint8_t t = inportb(PCI_VALUE_PORT + (field & 3));
|
||||
return t;
|
||||
}
|
||||
return 0xFFFF;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a PCI config value for the given bus/slot/function/offset
|
||||
*/
|
||||
uint16_t
|
||||
pci_read_word(
|
||||
uint32_t bus,
|
||||
uint32_t slot,
|
||||
uint32_t func,
|
||||
uint16_t offset
|
||||
) {
|
||||
uint32_t address = (uint32_t)((bus << 16) || (slot << 11) |
|
||||
(func << 8) | (offset & 0xFC) | ((uint32_t)0x80000000));
|
||||
outportl(PCI_CONFIG_ADDRESS, address);
|
||||
return (uint16_t)((inportl(PCI_CONFIG_DATA) >> ((offset & 2) * 8)) & 0xFFFF);
|
||||
uint16_t pci_find_type(uint32_t dev) {
|
||||
return (pci_read_field(dev, PCI_CLASS, 1) << 8) | pci_read_field(dev, PCI_SUBCLASS, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a PCI config value for the given bus/slot/function/offset
|
||||
*/
|
||||
void
|
||||
pci_write_word(
|
||||
uint32_t bus,
|
||||
uint32_t slot,
|
||||
uint32_t func,
|
||||
uint16_t offset,
|
||||
uint32_t data
|
||||
) {
|
||||
uint32_t address = (uint32_t)((bus << 16) || (slot << 11) |
|
||||
(func << 8) | (offset & 0xFC) | ((uint32_t)0x80000000));
|
||||
outportl(PCI_CONFIG_ADDRESS, address);
|
||||
outportl(PCI_CONFIG_DATA, data);
|
||||
const char * pci_vendor_lookup(unsigned short vendor_id) {
|
||||
for (unsigned int i = 0; i < PCI_VENTABLE_LEN; ++i) {
|
||||
if (PciVenTable[i].VenId == vendor_id) {
|
||||
return PciVenTable[i].VenFull;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
const char * pci_device_lookup(unsigned short vendor_id, unsigned short device_id) {
|
||||
for (unsigned int i = 0; i < PCI_DEVTABLE_LEN; ++i) {
|
||||
if (PciDevTable[i].VenId == vendor_id && PciDevTable[i].DevId == device_id) {
|
||||
return PciDevTable[i].ChipDesc;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void pci_scan_hit(pci_func_t f, uint32_t dev) {
|
||||
int dev_vend = (int)pci_read_field(dev, PCI_VENDOR_ID, 2);
|
||||
int dev_dvid = (int)pci_read_field(dev, PCI_DEVICE_ID, 2);
|
||||
|
||||
f(dev, dev_vend, dev_dvid);
|
||||
}
|
||||
|
||||
void pci_scan_func(pci_func_t f, int type, int bus, int slot, int func) {
|
||||
uint32_t dev = pci_box_device(bus, slot, func);
|
||||
if (type == -1 || type == pci_find_type(dev)) {
|
||||
pci_scan_hit(f, dev);
|
||||
}
|
||||
if (pci_find_type(dev) == PCI_TYPE_BRIDGE) {
|
||||
pci_scan_bus(f, type, pci_read_field(dev, PCI_SECONDARY_BUS, 1));
|
||||
}
|
||||
}
|
||||
|
||||
void pci_scan_slot(pci_func_t f, int type, int bus, int slot) {
|
||||
uint32_t dev = pci_box_device(bus, slot, 0);
|
||||
if (pci_read_field(dev, PCI_VENDOR_ID, 2) == PCI_NONE) {
|
||||
return;
|
||||
}
|
||||
pci_scan_func(f, type, bus, slot, 0);
|
||||
if (!pci_read_field(dev, PCI_HEADER_TYPE, 1)) {
|
||||
return;
|
||||
}
|
||||
for (int func = 1; func < 8; func++) {
|
||||
uint32_t dev = pci_box_device(bus, slot, func);
|
||||
if (pci_read_field(dev, PCI_VENDOR_ID, 2) != PCI_NONE) {
|
||||
pci_scan_func(f, type, bus, slot, func);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pci_scan_bus(pci_func_t f, int type, int bus) {
|
||||
for (int slot = 0; slot < 32; ++slot) {
|
||||
pci_scan_slot(f, type, bus, slot);
|
||||
}
|
||||
}
|
||||
|
||||
void pci_scan(pci_func_t f, int type) {
|
||||
pci_scan_bus(f, type, 0);
|
||||
|
||||
if (!pci_read_field(0, PCI_HEADER_TYPE, 1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int func = 1; func < 8; ++func) {
|
||||
uint32_t dev = pci_box_device(0, 0, func);
|
||||
if (pci_read_field(dev, PCI_VENDOR_ID, 2) != PCI_NONE) {
|
||||
pci_scan_bus(f, type, func);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
69
kernel/include/pci.h
Normal file
69
kernel/include/pci.h
Normal file
@ -0,0 +1,69 @@
|
||||
#ifndef _PCI_H
|
||||
#define _PCI_H
|
||||
|
||||
#define PCI_VENDOR_ID 0x00 // 2
|
||||
#define PCI_DEVICE_ID 0x02 // 2
|
||||
#define PCI_COMMAND 0x04 // 2
|
||||
#define PCI_STATUS 0x06 // 2
|
||||
#define PCI_REVISION_ID 0x08 // 1
|
||||
|
||||
#define PCI_PROG_IF 0x09 // 1
|
||||
#define PCI_SUBCLASS 0x0a // 1
|
||||
#define PCI_CLASS 0x0b // 1
|
||||
#define PCI_CACHE_LINE_SIZE 0x0c // 1
|
||||
#define PCI_LATENCY_TIMER 0x0d // 1
|
||||
#define PCI_HEADER_TYPE 0x0e // 1
|
||||
#define PCI_BIST 0x0f // 1
|
||||
#define PCI_BAR0 0x10 // 4
|
||||
#define PCI_BAR1 0x14 // 4
|
||||
#define PCI_BAR2 0x18 // 4
|
||||
#define PCI_BAR3 0x1C // 4
|
||||
#define PCI_BAR4 0x20 // 4
|
||||
#define PCI_BAR5 0x24 // 4
|
||||
|
||||
#define PCI_SECONDARY_BUS 0x09 // 1
|
||||
|
||||
#define PCI_HEADER_TYPE_DEVICE 0
|
||||
#define PCI_HEADER_TYPE_BRIDGE 1
|
||||
#define PCI_HEADER_TYPE_CARDBUS 2
|
||||
|
||||
#define PCI_TYPE_BRIDGE 0x0604
|
||||
#define PCI_TYPE_SATA 0x0106
|
||||
|
||||
#define PCI_ADDRESS_PORT 0xCF8
|
||||
#define PCI_VALUE_PORT 0xCFC
|
||||
|
||||
#define PCI_NONE 0xFFFF
|
||||
|
||||
typedef void (*pci_func_t)(uint32_t device, uint16_t vendor_id, uint16_t device_id);
|
||||
|
||||
static inline int pci_extract_bus(uint32_t device) {
|
||||
return (uint8_t)((device >> 16));
|
||||
}
|
||||
static inline int pci_extract_slot(uint32_t device) {
|
||||
return (uint8_t)((device >> 8));
|
||||
}
|
||||
static inline int pci_extract_func(uint32_t device) {
|
||||
return (uint8_t)(device);
|
||||
}
|
||||
|
||||
static inline uint32_t pci_get_addr(uint32_t device, int field) {
|
||||
return 0x80000000 | (pci_extract_bus(device) << 16) | (pci_extract_slot(device) << 11) | (pci_extract_func(device) << 8) | ((field) & 0xFC);
|
||||
}
|
||||
|
||||
static inline uint32_t pci_box_device(int bus, int slot, int func) {
|
||||
return (uint32_t)((bus << 16) | (slot << 8) | func);
|
||||
}
|
||||
|
||||
uint32_t pci_read_field(uint32_t device, int field, int size);
|
||||
uint16_t pci_find_type(uint32_t dev);
|
||||
const char * pci_vendor_lookup(unsigned short vendor_id);
|
||||
const char * pci_device_lookup(unsigned short vendor_id, unsigned short device_id);
|
||||
void pci_scan_hit(pci_func_t f, uint32_t dev);
|
||||
void pci_scan_func(pci_func_t f, int type, int bus, int slot, int func);
|
||||
void pci_scan_slot(pci_func_t f, int type, int bus, int slot);
|
||||
void pci_scan_bus(pci_func_t f, int type, int bus);
|
||||
void pci_scan(pci_func_t f, int type);
|
||||
|
||||
|
||||
#endif
|
7053
kernel/include/pci_list.h
Normal file
7053
kernel/include/pci_list.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -201,6 +201,8 @@ extern void page_fault(struct regs *r);
|
||||
extern void dma_frame(page_t * page, int, int, uintptr_t);
|
||||
extern void debug_print_directory(void);
|
||||
|
||||
int debug_shell_start(void);
|
||||
|
||||
void heap_install(void);
|
||||
|
||||
void alloc_frame(page_t *page, int is_kernel, int is_writeable);
|
||||
|
@ -53,7 +53,6 @@ void args_parse(char * _arg) {
|
||||
int argc = tokenize(arg, " ", argv);
|
||||
|
||||
/* New let's parse the tokens into the arguments list so we can index by key */
|
||||
/* TODO I really need a dictionary/hashmap implementation */
|
||||
|
||||
if (!kernel_args_map) {
|
||||
kernel_args_map = hashmap_create(10);
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <termios.h>
|
||||
#include <tokenize.h>
|
||||
#include <hashmap.h>
|
||||
#include <pci.h>
|
||||
|
||||
#include <debug_shell.h>
|
||||
|
||||
@ -86,12 +87,6 @@ int debug_shell_readline(fs_node_t * dev, char * linebuf, int max) {
|
||||
*/
|
||||
void debug_shell_run_sh(void * data, char * name) {
|
||||
|
||||
fs_node_t * tty = (fs_node_t *)data;
|
||||
|
||||
current_process->fds->entries[0] = tty;
|
||||
current_process->fds->entries[1] = tty;
|
||||
current_process->fds->entries[2] = tty;
|
||||
|
||||
char * argv[] = {
|
||||
"/bin/sh",
|
||||
NULL
|
||||
@ -122,7 +117,7 @@ hashmap_t * shell_commands_map = NULL;
|
||||
* Shell commands
|
||||
*/
|
||||
static int shell_create_userspace_shell(fs_node_t * tty, int argc, char * argv[]) {
|
||||
int pid = create_kernel_tasklet(debug_shell_run_sh, "[[k-sh]]", tty);
|
||||
int pid = create_kernel_tasklet(debug_shell_run_sh, "[[k-sh]]", NULL);
|
||||
fs_printf(tty, "Shell started with pid = %d\n", pid);
|
||||
process_t * child_task = process_from_pid(pid);
|
||||
sleep_on(child_task->wait_queue);
|
||||
@ -294,6 +289,55 @@ static int shell_anagrams(fs_node_t * tty, int argc, char * argv[]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned short pciConfigReadWord (unsigned short bus, unsigned short slot,
|
||||
unsigned short func, unsigned short offset)
|
||||
{
|
||||
unsigned long address;
|
||||
unsigned long lbus = (unsigned long)bus;
|
||||
unsigned long lslot = (unsigned long)slot;
|
||||
unsigned long lfunc = (unsigned long)func;
|
||||
unsigned short tmp = 0;
|
||||
|
||||
/* create configuration address as per Figure 1 */
|
||||
address = (unsigned long)((lbus << 16) | (lslot << 11) |
|
||||
(lfunc << 8) | (offset & 0xfc) | ((uint32_t)0x80000000));
|
||||
|
||||
/* write out the address */
|
||||
outportl(0xCF8, address);
|
||||
/* read in the data */
|
||||
/* (offset & 2) * 8) = 0 will choose the fisrt word of the 32 bits register */
|
||||
tmp = (unsigned short)((inportl(0xCFC) >> ((offset & 2) * 8)) & 0xffff);
|
||||
return (tmp);
|
||||
}
|
||||
|
||||
static void scan_hit_list(uint32_t device, uint16_t vendorid, uint16_t deviceid) {
|
||||
|
||||
fs_node_t * tty = current_process->fds->entries[0];
|
||||
|
||||
fs_printf(tty, "%x:%x.%x (%x, %x:%x) %s %s\n",
|
||||
(int)pci_extract_bus(device),
|
||||
(int)pci_extract_slot(device),
|
||||
(int)pci_extract_func(device),
|
||||
(int)pci_find_type(device),
|
||||
vendorid,
|
||||
deviceid,
|
||||
pci_vendor_lookup(vendorid),
|
||||
pci_device_lookup(vendorid,deviceid));
|
||||
|
||||
fs_printf(tty, " BAR0: 0x%x\n", pci_read_field(device, PCI_BAR0, 4));
|
||||
fs_printf(tty, " BAR1: 0x%x\n", pci_read_field(device, PCI_BAR1, 4));
|
||||
fs_printf(tty, " BAR2: 0x%x\n", pci_read_field(device, PCI_BAR2, 4));
|
||||
fs_printf(tty, " BAR3: 0x%x\n", pci_read_field(device, PCI_BAR3, 4));
|
||||
fs_printf(tty, " BAR4: 0x%x\n", pci_read_field(device, PCI_BAR4, 4));
|
||||
fs_printf(tty, " BAR6: 0x%x\n", pci_read_field(device, PCI_BAR5, 4));
|
||||
|
||||
}
|
||||
|
||||
static int shell_pci(fs_node_t * tty, int argc, char * argv[]) {
|
||||
pci_scan(&scan_hit_list, -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct shell_command shell_commands[] = {
|
||||
{"shell", &shell_create_userspace_shell,
|
||||
"Runs a userspace shell on this tty."},
|
||||
@ -311,6 +355,8 @@ static struct shell_command shell_commands[] = {
|
||||
"Enable serial logging."},
|
||||
{"anagrams", &shell_anagrams,
|
||||
"Demo of hashmaps and lists. Give a list of words, get a grouping of anagrams."},
|
||||
{"pci", &shell_pci,
|
||||
"PCI stuff"},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
@ -448,6 +494,10 @@ void debug_shell_run(void * data, char * name) {
|
||||
/* Set the device to be the actual TTY slave */
|
||||
tty = current_process->fds->entries[slave];
|
||||
|
||||
current_process->fds->entries[0] = tty;
|
||||
current_process->fds->entries[1] = tty;
|
||||
current_process->fds->entries[2] = tty;
|
||||
|
||||
/* Initialize the shell commands map */
|
||||
if (!shell_commands_map) {
|
||||
shell_commands_map = hashmap_create(10);
|
||||
|
@ -170,7 +170,7 @@ void outports(unsigned short _port, unsigned short _data) {
|
||||
}
|
||||
|
||||
unsigned int inportl(unsigned short _port) {
|
||||
unsigned short rv;
|
||||
unsigned int rv;
|
||||
asm volatile ("inl %%dx, %%eax" : "=a" (rv) : "dN" (_port));
|
||||
return rv;
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <fs.h>
|
||||
#include <types.h>
|
||||
#include <logging.h>
|
||||
#include <pci.h>
|
||||
|
||||
#define PREFERRED_VY 4096
|
||||
#define PREFERRED_B 32
|
||||
@ -45,8 +46,16 @@ uint16_t bochs_current_scroll(void) {
|
||||
return current_scroll;
|
||||
}
|
||||
|
||||
void
|
||||
graphics_install_bochs(uint16_t resolution_x, uint16_t resolution_y) {
|
||||
void bochs_scan_pci(uint32_t device, uint16_t v, uint16_t d) {
|
||||
if (v == 0x1234 && d == 0x1111) {
|
||||
uintptr_t t = pci_read_field(device, PCI_BAR0, 4);
|
||||
if (t > 0) {
|
||||
lfb_vid_memory = (uint8_t *)(t & 0xFFFFFFF0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void graphics_install_bochs(uint16_t resolution_x, uint16_t resolution_y) {
|
||||
debug_print(NOTICE, "Setting up BOCHS/QEMU graphics controller...");
|
||||
outports(0x1CE, 0x00);
|
||||
uint16_t i = inports(0x1CF);
|
||||
@ -74,24 +83,36 @@ graphics_install_bochs(uint16_t resolution_x, uint16_t resolution_y) {
|
||||
outports(0x1CE, 0x04);
|
||||
outports(0x1CF, 0x41);
|
||||
|
||||
/* XXX: Massive hack */
|
||||
uint32_t * text_vid_mem = (uint32_t *)0xA0000;
|
||||
text_vid_mem[0] = 0xA5ADFACE;
|
||||
pci_scan(bochs_scan_pci, -1);
|
||||
|
||||
for (uintptr_t fb_offset = 0xE0000000; fb_offset < 0xFF000000; fb_offset += 0x01000000) {
|
||||
if (lfb_vid_memory) {
|
||||
/* Enable the higher memory */
|
||||
uintptr_t fb_offset = (uintptr_t)lfb_vid_memory;
|
||||
for (uintptr_t i = fb_offset; i <= fb_offset + 0xFF0000; i += 0x1000) {
|
||||
dma_frame(get_page(i, 1, kernel_directory), 0, 1, i);
|
||||
}
|
||||
|
||||
/* Go find it */
|
||||
for (uintptr_t x = fb_offset; x < fb_offset + 0xFF0000; x += 0x1000) {
|
||||
if (((uintptr_t *)x)[0] == 0xA5ADFACE) {
|
||||
lfb_vid_memory = (uint8_t *)x;
|
||||
goto mem_found;
|
||||
goto mem_found;
|
||||
} else {
|
||||
/* XXX: Massive hack */
|
||||
|
||||
uint32_t * text_vid_mem = (uint32_t *)0xA0000;
|
||||
text_vid_mem[0] = 0xA5ADFACE;
|
||||
|
||||
for (uintptr_t fb_offset = 0xE0000000; fb_offset < 0xFF000000; fb_offset += 0x01000000) {
|
||||
/* Enable the higher memory */
|
||||
for (uintptr_t i = fb_offset; i <= fb_offset + 0xFF0000; i += 0x1000) {
|
||||
dma_frame(get_page(i, 1, kernel_directory), 0, 1, i);
|
||||
}
|
||||
|
||||
/* Go find it */
|
||||
for (uintptr_t x = fb_offset; x < fb_offset + 0xFF0000; x += 0x1000) {
|
||||
if (((uintptr_t *)x)[0] == 0xA5ADFACE) {
|
||||
lfb_vid_memory = (uint8_t *)x;
|
||||
goto mem_found;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
mem_found:
|
||||
|
Loading…
Reference in New Issue
Block a user