get ide controllers from pci instead of assuming compatibility mode; name pata drives based on order discovered instead of controller
This commit is contained in:
parent
7d90ac7d3d
commit
6d9c3f7794
10 changed files with 251 additions and 199 deletions
|
|
@ -4,4 +4,4 @@ quiet: yes
|
||||||
/Calcite
|
/Calcite
|
||||||
protocol: limine
|
protocol: limine
|
||||||
path: boot():/calcite/kernel.elf
|
path: boot():/calcite/kernel.elf
|
||||||
cmdline: root-drive=pata2,root-fs=iso9660
|
cmdline: root-drive=pata0,root-fs=iso9660
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
#include "panic.h"
|
#include "panic.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include "heap.h"
|
#include "heap.h"
|
||||||
#include "pata.h"
|
#include "pci.h"
|
||||||
#include "ps2.h"
|
#include "ps2.h"
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
|
|
||||||
|
|
@ -273,9 +273,9 @@ static const char *cmdline_look_up(const char *key) {
|
||||||
register_syscall(SYSCALL_CREATE_THREAD, (void *)&syscall_create_thread);
|
register_syscall(SYSCALL_CREATE_THREAD, (void *)&syscall_create_thread);
|
||||||
register_syscall(SYSCALL_GET_ENVVAR, (void *)&syscall_get_envvar);
|
register_syscall(SYSCALL_GET_ENVVAR, (void *)&syscall_get_envvar);
|
||||||
|
|
||||||
//probe for drives
|
//probe pci devices
|
||||||
|
|
||||||
probe_pata_drives();
|
probe_pci();
|
||||||
|
|
||||||
//load root file system
|
//load root file system
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,130 +0,0 @@
|
||||||
; Calcite, src/kernel/pata.asm
|
|
||||||
; Copyright 2025 Benji Dial
|
|
||||||
;
|
|
||||||
; This program is free software: you can redistribute it and/or modify
|
|
||||||
; it under the terms of the GNU General Public License as published by
|
|
||||||
; the Free Software Foundation, either version 3 of the License, or
|
|
||||||
; (at your option) any later version.
|
|
||||||
;
|
|
||||||
; This program is distributed in the hope that it will be useful, but
|
|
||||||
; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
; for more details.
|
|
||||||
;
|
|
||||||
; You should have received a copy of the GNU General Public License along
|
|
||||||
; with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
|
|
||||||
bits 64
|
|
||||||
default rel
|
|
||||||
|
|
||||||
section .text
|
|
||||||
|
|
||||||
;referenced in pata.c
|
|
||||||
global pata_set_device
|
|
||||||
pata_set_device:
|
|
||||||
mov dx, 0x01f6
|
|
||||||
shl dil, 7
|
|
||||||
xor dl, dil
|
|
||||||
mov al, sil
|
|
||||||
out dx, al
|
|
||||||
ret
|
|
||||||
|
|
||||||
;referenced in pata.c
|
|
||||||
global pata_set_features
|
|
||||||
pata_set_features:
|
|
||||||
mov dx, 0x01f1
|
|
||||||
shl dil, 7
|
|
||||||
xor dl, dil
|
|
||||||
mov al, sil
|
|
||||||
out dx, al
|
|
||||||
ret
|
|
||||||
|
|
||||||
;referenced in pata.c
|
|
||||||
global pata_set_lba
|
|
||||||
pata_set_lba:
|
|
||||||
|
|
||||||
mov dx, 0x01f3
|
|
||||||
shl dil, 7
|
|
||||||
xor dl, dil
|
|
||||||
mov eax, esi
|
|
||||||
out dx, al
|
|
||||||
|
|
||||||
inc dx
|
|
||||||
shr eax, 8
|
|
||||||
out dx, al
|
|
||||||
|
|
||||||
inc dx
|
|
||||||
shr ax, 8
|
|
||||||
out dx, al
|
|
||||||
|
|
||||||
ret
|
|
||||||
|
|
||||||
;referenced in pata.c
|
|
||||||
global pata_set_command
|
|
||||||
pata_set_command:
|
|
||||||
mov dx, 0x01f7
|
|
||||||
shl dil, 7
|
|
||||||
xor dl, dil
|
|
||||||
mov al, sil
|
|
||||||
out dx, al
|
|
||||||
ret
|
|
||||||
|
|
||||||
;referenced in pata.c
|
|
||||||
global pata_read_status
|
|
||||||
pata_read_status:
|
|
||||||
mov dx, 0x01f7
|
|
||||||
shl dil, 7
|
|
||||||
xor dl, dil
|
|
||||||
in al, dx
|
|
||||||
ret
|
|
||||||
|
|
||||||
;referenced in pata.c
|
|
||||||
global pata_read_error
|
|
||||||
pata_read_error:
|
|
||||||
mov dx, 0x01f1
|
|
||||||
shl dil, 7
|
|
||||||
xor dl, dil
|
|
||||||
in al, dx
|
|
||||||
ret
|
|
||||||
|
|
||||||
;referenced in pata.c
|
|
||||||
global pata_read_lba
|
|
||||||
pata_read_lba:
|
|
||||||
|
|
||||||
mov dx, 0x01f5
|
|
||||||
shl dil, 7
|
|
||||||
xor dl, dil
|
|
||||||
xor eax, eax
|
|
||||||
in al, dx
|
|
||||||
|
|
||||||
dec dx
|
|
||||||
shl ax, 8
|
|
||||||
in al, dx
|
|
||||||
|
|
||||||
dec dx
|
|
||||||
shl eax, 8
|
|
||||||
in al, dx
|
|
||||||
|
|
||||||
ret
|
|
||||||
|
|
||||||
;referenced in pata.c
|
|
||||||
global pata_read_data
|
|
||||||
pata_read_data:
|
|
||||||
movzx rcx, dx
|
|
||||||
mov dx, 0x01f0
|
|
||||||
shl dil, 7
|
|
||||||
xor dl, dil
|
|
||||||
mov rdi, rsi
|
|
||||||
rep insw
|
|
||||||
ret
|
|
||||||
|
|
||||||
;referenced in pata.c
|
|
||||||
global pata_write_data
|
|
||||||
pata_write_data:
|
|
||||||
movzx rcx, dx
|
|
||||||
mov dx, 0x01f0
|
|
||||||
shl dil, 7
|
|
||||||
xor dl, dil
|
|
||||||
rep outsw
|
|
||||||
ret
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
* with this program. If not, see <https://www.gnu.org/licenses/>.
|
* with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "pci.h"
|
||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
#include "drives.h"
|
#include "drives.h"
|
||||||
#include "panic.h"
|
#include "panic.h"
|
||||||
|
|
@ -22,41 +23,25 @@
|
||||||
#include "pata.h"
|
#include "pata.h"
|
||||||
|
|
||||||
//some relevant sources:
|
//some relevant sources:
|
||||||
|
// https://www.isdaman.com/alsos/hardware/hdc/pciide.pdf
|
||||||
// ANSI: AT Attachment 8 - ATA/ATAPI Command Set
|
// ANSI: AT Attachment 8 - ATA/ATAPI Command Set
|
||||||
// Seagate: SCSI Commands Reference Manual
|
// Seagate: SCSI Commands Reference Manual
|
||||||
// OSDev Wiki: ATAPI, PCI IDE Controller
|
// OSDev Wiki: ATAPI, PCI IDE Controller
|
||||||
|
|
||||||
//in any function that takes a "controller", 0 means the primary controller
|
|
||||||
//and 1 means the secondary controller. in any function that takes a "drive",
|
|
||||||
//bit 1 is the controller, and bit 0 is bit 4 of the device register.
|
|
||||||
|
|
||||||
//all defined in pata.asm
|
|
||||||
void pata_set_device(uint8_t controller, uint8_t value);
|
|
||||||
void pata_set_features(uint8_t controller, uint8_t value);
|
|
||||||
void pata_set_lba(uint8_t controller, uint32_t value);
|
|
||||||
void pata_set_command(uint8_t controller, uint8_t value);
|
|
||||||
uint8_t pata_read_status(uint8_t controller);
|
|
||||||
uint8_t pata_read_error(uint8_t controller);
|
|
||||||
uint32_t pata_read_lba(uint8_t controller);
|
|
||||||
void pata_read_data(
|
|
||||||
uint8_t controller, uint16_t *buffer, uint16_t word_count);
|
|
||||||
void pata_write_data(
|
|
||||||
uint8_t controller, const uint16_t *buffer, uint16_t word_count);
|
|
||||||
|
|
||||||
enum pata_result {
|
enum pata_result {
|
||||||
PR_SUCCESS,
|
PR_SUCCESS,
|
||||||
PR_NO_CONTROLLER,
|
PR_NO_CONTROLLER,
|
||||||
PR_ABORTED
|
PR_ABORTED
|
||||||
};
|
};
|
||||||
|
|
||||||
enum pata_result wait_pio(uint8_t controller) {
|
enum pata_result wait_pio(uint16_t command_block_base) {
|
||||||
while (1) {
|
while (1) {
|
||||||
uint8_t status = pata_read_status(controller);
|
uint8_t status = inb(command_block_base + 7);
|
||||||
//0x00 happens in qemu, 0x7f happens in virtualbox
|
//0x00 happens in qemu, 0x7f happens in virtualbox
|
||||||
if (status == 0x00 || status == 0x7f)
|
if (status == 0x00 || status == 0x7f)
|
||||||
return PR_NO_CONTROLLER;
|
return PR_NO_CONTROLLER;
|
||||||
if (status & 0x01) {
|
if (status & 0x01) {
|
||||||
uint8_t error = pata_read_error(controller);
|
uint8_t error = inb(command_block_base + 1);
|
||||||
if (error == 0x04)
|
if (error == 0x04)
|
||||||
return PR_ABORTED;
|
return PR_ABORTED;
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
|
|
@ -69,51 +54,50 @@ enum pata_result wait_pio(uint8_t controller) {
|
||||||
|
|
||||||
//buffer should have room for 256 words.
|
//buffer should have room for 256 words.
|
||||||
static enum pata_result
|
static enum pata_result
|
||||||
pata_identify_packet_device(uint8_t drive, uint16_t *buffer) {
|
pata_identify_packet_device(uint16_t command_block_base, uint8_t device_byte, uint16_t *buffer) {
|
||||||
|
|
||||||
uint8_t controller = drive >> 1;
|
outb(command_block_base + 6, device_byte);
|
||||||
|
outb(command_block_base + 7, 0xa1);
|
||||||
|
|
||||||
pata_set_device(controller, (drive & 0x01) << 4);
|
enum pata_result result = wait_pio(command_block_base);
|
||||||
pata_set_command(controller, 0xa1);
|
|
||||||
|
|
||||||
enum pata_result result = wait_pio(controller);
|
|
||||||
if (result != PR_SUCCESS)
|
if (result != PR_SUCCESS)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
pata_read_data(controller, buffer, 256);
|
insw(command_block_base, buffer, 256);
|
||||||
return PR_SUCCESS;
|
return PR_SUCCESS;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum pata_result patapi_read_capacity(
|
static enum pata_result patapi_read_capacity(
|
||||||
uint8_t drive, uint32_t *max_block_out, uint32_t *block_size_out) {
|
uint16_t command_block_base, uint8_t device_byte, uint32_t *max_block_out, uint32_t *block_size_out) {
|
||||||
|
|
||||||
uint8_t controller = drive >> 1;
|
outb(command_block_base + 6, device_byte);
|
||||||
|
outb(command_block_base + 1, 0);
|
||||||
|
outb(command_block_base + 3, 0);
|
||||||
|
outb(command_block_base + 4, 8);
|
||||||
|
outb(command_block_base + 5, 0);
|
||||||
|
outb(command_block_base + 7, 0xa0);
|
||||||
|
|
||||||
pata_set_device(controller, (drive & 0x01) << 4);
|
enum pata_result result = wait_pio(command_block_base);
|
||||||
pata_set_features(controller, 0);
|
|
||||||
pata_set_lba(controller, 8 << 8);
|
|
||||||
pata_set_command(controller, 0xa0);
|
|
||||||
|
|
||||||
enum pata_result result = wait_pio(controller);
|
|
||||||
if (result != PR_SUCCESS)
|
if (result != PR_SUCCESS)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
uint8_t cmd[12] = {
|
uint8_t cmd[12] = {
|
||||||
0x25, 0, 0, 0, 0, 0,
|
0x25, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0 };
|
0, 0, 0, 0, 0, 0 };
|
||||||
pata_write_data(controller, (uint16_t *)cmd, 6);
|
outsw(command_block_base, cmd, 6);
|
||||||
|
|
||||||
result = wait_pio(controller);
|
result = wait_pio(command_block_base);
|
||||||
if (result != PR_SUCCESS)
|
if (result != PR_SUCCESS)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
uint32_t actual_response_size = pata_read_lba(controller) >> 8;
|
uint32_t actual_response_size =
|
||||||
|
inb(command_block_base + 4) | (inb(command_block_base + 5) << 8);
|
||||||
if (actual_response_size != 8)
|
if (actual_response_size != 8)
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
|
|
||||||
uint32_t response[2];
|
uint32_t response[2];
|
||||||
pata_read_data(controller, (uint16_t *)response, 4);
|
insw(command_block_base, response, 4);
|
||||||
|
|
||||||
*max_block_out = end_swap_u32(response[0]);
|
*max_block_out = end_swap_u32(response[0]);
|
||||||
*block_size_out = end_swap_u32(response[1]);
|
*block_size_out = end_swap_u32(response[1]);
|
||||||
|
|
@ -122,16 +106,17 @@ static enum pata_result patapi_read_capacity(
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum pata_result patapi_read(
|
static enum pata_result patapi_read(
|
||||||
uint8_t drive, uint16_t block_size, uint32_t start_block, uint32_t block_count, void *buffer) {
|
uint16_t command_block_base, uint8_t device_byte, uint16_t block_size,
|
||||||
|
uint32_t start_block, uint32_t block_count, void *buffer) {
|
||||||
|
|
||||||
uint8_t controller = drive >> 1;
|
outb(command_block_base + 6, device_byte);
|
||||||
|
outb(command_block_base + 1, 0);
|
||||||
|
outb(command_block_base + 3, 0);
|
||||||
|
outb(command_block_base + 4, block_size & 0xff);
|
||||||
|
outb(command_block_base + 5, block_size >> 8);
|
||||||
|
outb(command_block_base + 7, 0xa0);
|
||||||
|
|
||||||
pata_set_device(controller, (drive & 0x01) << 4);
|
enum pata_result result = wait_pio(command_block_base);
|
||||||
pata_set_features(controller, 0);
|
|
||||||
pata_set_lba(controller, (uint32_t)block_size << 8);
|
|
||||||
pata_set_command(controller, 0xa0);
|
|
||||||
|
|
||||||
enum pata_result result = wait_pio(controller);
|
|
||||||
if (result != PR_SUCCESS)
|
if (result != PR_SUCCESS)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
|
@ -146,19 +131,21 @@ static enum pata_result patapi_read(
|
||||||
(block_count >> 8) & 0xff,
|
(block_count >> 8) & 0xff,
|
||||||
block_count & 0xff,
|
block_count & 0xff,
|
||||||
0, 0 };
|
0, 0 };
|
||||||
pata_write_data(controller, (uint16_t *)cmd, 8);
|
outsw(command_block_base, cmd, 6);
|
||||||
|
|
||||||
for (uint32_t i = 0; i < block_count; ++i) {
|
for (uint32_t i = 0; i < block_count; ++i) {
|
||||||
|
|
||||||
result = wait_pio(controller);
|
result = wait_pio(command_block_base);
|
||||||
if (result != PR_SUCCESS)
|
if (result != PR_SUCCESS)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
uint32_t actual_response_size = pata_read_lba(controller) >> 8;
|
uint32_t actual_response_size =
|
||||||
|
inb(command_block_base + 4) | (inb(command_block_base + 5) << 8);
|
||||||
|
|
||||||
if (actual_response_size != block_size)
|
if (actual_response_size != block_size)
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
|
|
||||||
pata_read_data(controller, (uint16_t *)(buffer + i * block_size), block_size / 2);
|
insw(command_block_base, buffer + i * block_size, block_size / 2);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -169,7 +156,8 @@ static enum pata_result patapi_read(
|
||||||
static uint16_t ipd_buffer[256];
|
static uint16_t ipd_buffer[256];
|
||||||
|
|
||||||
struct pata_driver_info {
|
struct pata_driver_info {
|
||||||
uint8_t drive;
|
uint16_t command_block_base;
|
||||||
|
uint8_t device_byte;
|
||||||
};
|
};
|
||||||
|
|
||||||
static enum drive_access_result read_blocks_patapi(
|
static enum drive_access_result read_blocks_patapi(
|
||||||
|
|
@ -179,30 +167,36 @@ static enum drive_access_result read_blocks_patapi(
|
||||||
if (count >= (1ULL << 32) || start >= (1ULL << 32))
|
if (count >= (1ULL << 32) || start >= (1ULL << 32))
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
|
|
||||||
uint8_t drive = ((const struct pata_driver_info *)drive_info->driver_info)->drive;
|
const struct pata_driver_info *driver_info = drive_info->driver_info;
|
||||||
|
|
||||||
return
|
return
|
||||||
patapi_read(
|
patapi_read(
|
||||||
drive, drive_info->block_size,
|
driver_info->command_block_base, driver_info->device_byte,
|
||||||
start, count, buffer) == PR_SUCCESS
|
drive_info->block_size, start, count, buffer) == PR_SUCCESS
|
||||||
? DAR_SUCCESS : DAR_HARDWARE_ERROR;
|
? DAR_SUCCESS : DAR_HARDWARE_ERROR;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void probe_pata_drive(uint8_t drive) {
|
int next_pata_drive_number = 0;
|
||||||
|
|
||||||
if (pata_identify_packet_device(drive, ipd_buffer) != PR_SUCCESS)
|
static void probe_pata_drive(uint16_t command_block_base, uint8_t device_byte) {
|
||||||
|
|
||||||
|
if (pata_identify_packet_device(command_block_base, device_byte, ipd_buffer) != PR_SUCCESS)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uint32_t max_block, block_size;
|
uint32_t max_block, block_size;
|
||||||
if (patapi_read_capacity(drive, &max_block, &block_size) != PR_SUCCESS)
|
if (patapi_read_capacity(
|
||||||
|
command_block_base, device_byte, &max_block, &block_size) != PR_SUCCESS)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (next_pata_drive_number > 9)
|
||||||
|
panic("TODO")
|
||||||
|
|
||||||
struct drive_info *di = add_drive();
|
struct drive_info *di = add_drive();
|
||||||
|
|
||||||
char *name = heap_alloc(6);
|
char *name = heap_alloc(6);
|
||||||
memcpy(name, "pata", 4);
|
memcpy(name, "pata", 4);
|
||||||
name[4] = '0' + drive;
|
name[4] = '0' + next_pata_drive_number++;
|
||||||
name[5] = 0;
|
name[5] = 0;
|
||||||
di->name = name;
|
di->name = name;
|
||||||
|
|
||||||
|
|
@ -211,14 +205,38 @@ static void probe_pata_drive(uint8_t drive) {
|
||||||
|
|
||||||
struct pata_driver_info *driver_info =
|
struct pata_driver_info *driver_info =
|
||||||
heap_alloc(sizeof(struct pata_driver_info));
|
heap_alloc(sizeof(struct pata_driver_info));
|
||||||
driver_info->drive = drive;
|
driver_info->command_block_base = command_block_base;
|
||||||
|
driver_info->device_byte = device_byte;
|
||||||
di->driver_info = driver_info;
|
di->driver_info = driver_info;
|
||||||
|
|
||||||
di->read_blocks = &read_blocks_patapi;
|
di->read_blocks = &read_blocks_patapi;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void probe_pata_drives() {
|
void probe_pata_drives(uint32_t pci_address_base, uint32_t pci_class_etc) {
|
||||||
for (int i = 0; i < 4; ++i)
|
|
||||||
probe_pata_drive(i);
|
if (pci_class_etc & 0x00000100) {
|
||||||
|
uint32_t bar = read_pci_config(pci_address_base + 0x10);
|
||||||
|
if ((bar & 0xffff0003) != 0x00000001)
|
||||||
|
panic("TODO")
|
||||||
|
probe_pata_drive(bar & 0xfffc, 0x00);
|
||||||
|
probe_pata_drive(bar & 0xfffc, 0x10);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
probe_pata_drive(0x01f0, 0x00);
|
||||||
|
probe_pata_drive(0x01f0, 0x10);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pci_class_etc & 0x00000400) {
|
||||||
|
uint32_t bar = read_pci_config(pci_address_base + 0x18);
|
||||||
|
if ((bar & 0xffff0003) != 0x00000001)
|
||||||
|
panic("TODO")
|
||||||
|
probe_pata_drive(bar & 0xfffc, 0x00);
|
||||||
|
probe_pata_drive(bar & 0xfffc, 0x10);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
probe_pata_drive(0x0170, 0x00);
|
||||||
|
probe_pata_drive(0x0170, 0x10);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,5 +19,5 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
//probes for all four pata drives and adds any that exist to drives.h
|
//probes for pata drives on this "card" and adds any that exist to drives.h
|
||||||
void probe_pata_drives();
|
void probe_pata_drives(uint32_t pci_address_base, uint32_t pci_class_etc);
|
||||||
|
|
|
||||||
40
src/kernel/pci.asm
Normal file
40
src/kernel/pci.asm
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
; Calcite, src/kernel/pci.asm
|
||||||
|
; Copyright 2025 Benji Dial
|
||||||
|
;
|
||||||
|
; This program is free software: you can redistribute it and/or modify
|
||||||
|
; it under the terms of the GNU General Public License as published by
|
||||||
|
; the Free Software Foundation, either version 3 of the License, or
|
||||||
|
; (at your option) any later version.
|
||||||
|
;
|
||||||
|
; This program is distributed in the hope that it will be useful, but
|
||||||
|
; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
; for more details.
|
||||||
|
;
|
||||||
|
; You should have received a copy of the GNU General Public License along
|
||||||
|
; with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
bits 64
|
||||||
|
default rel
|
||||||
|
|
||||||
|
section .text
|
||||||
|
|
||||||
|
global read_pci_config
|
||||||
|
read_pci_config:
|
||||||
|
mov dx, 0x0cf8
|
||||||
|
mov eax, edi
|
||||||
|
out dx, eax
|
||||||
|
mov dx, 0x0cfc
|
||||||
|
in eax, dx
|
||||||
|
ret
|
||||||
|
|
||||||
|
global write_pci_config
|
||||||
|
write_pci_config:
|
||||||
|
mov dx, 0x0cf8
|
||||||
|
mov eax, edi
|
||||||
|
out dx, eax
|
||||||
|
mov dx, 0x0cfc
|
||||||
|
mov eax, esi
|
||||||
|
out dx, eax
|
||||||
|
ret
|
||||||
59
src/kernel/pci.c
Normal file
59
src/kernel/pci.c
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
/* Calcite, src/kernel/pci.c
|
||||||
|
* Copyright 2025 Benji Dial
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pata.h"
|
||||||
|
#include "pci.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
static void probe_bus(uint32_t bus_address_base) {
|
||||||
|
|
||||||
|
for (uint32_t device_address_base = bus_address_base;
|
||||||
|
device_address_base < bus_address_base + 0x00010000;
|
||||||
|
device_address_base += 0x00000800)
|
||||||
|
for (uint32_t function_address_base = device_address_base;
|
||||||
|
function_address_base < device_address_base + 0x00000800;
|
||||||
|
function_address_base += 0x00000100) {
|
||||||
|
|
||||||
|
uint8_t header_type = (read_pci_config(function_address_base | 0x0c) >> 16) & 0xff;
|
||||||
|
if (header_type == 0xff)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if ((header_type & 0x7f) == 0x01)
|
||||||
|
//this is a pci-to-pci bridge
|
||||||
|
probe_bus((read_pci_config(function_address_base | 0x18) >> 8) & 0xff);
|
||||||
|
|
||||||
|
else if ((header_type & 0x7f) == 0x00) {
|
||||||
|
//this is a normal function
|
||||||
|
uint32_t class_etc = read_pci_config(function_address_base | 0x08);
|
||||||
|
switch (class_etc & 0xffff0000) {
|
||||||
|
case 0x01010000:
|
||||||
|
probe_pata_drives(function_address_base, class_etc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(header_type & 0x80))
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void probe_pci() {
|
||||||
|
probe_bus(0x80000000);
|
||||||
|
}
|
||||||
32
src/kernel/pci.h
Normal file
32
src/kernel/pci.h
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
/* Calcite, src/kernel/pci.h
|
||||||
|
* Copyright 2025 Benji Dial
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
//reads one dword from config space.
|
||||||
|
//address is 0x8000000 | (bus << 16) | (device << 11) | (function << 8) | (bytes into that function's space).
|
||||||
|
//bytes into that function's space must be dword-aligned.
|
||||||
|
uint32_t read_pci_config(uint32_t address);
|
||||||
|
|
||||||
|
//writes one dword to config space.
|
||||||
|
//address is 0x8000000 | (bus << 16) | (device << 11) | (function << 8) | (bytes into that function's space).
|
||||||
|
//bytes into that function's space must be dword-aligned.
|
||||||
|
void write_pci_config(uint32_t address, uint32_t value);
|
||||||
|
|
||||||
|
void probe_pci();
|
||||||
|
|
@ -32,3 +32,31 @@ memzero:
|
||||||
mov rcx, rsi
|
mov rcx, rsi
|
||||||
rep stosb
|
rep stosb
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
global outb
|
||||||
|
outb:
|
||||||
|
mov dx, di
|
||||||
|
mov al, sil
|
||||||
|
out dx, al
|
||||||
|
ret
|
||||||
|
|
||||||
|
global inb
|
||||||
|
inb:
|
||||||
|
mov dx, di
|
||||||
|
in al, dx
|
||||||
|
ret
|
||||||
|
|
||||||
|
global outsw
|
||||||
|
outsw:
|
||||||
|
mov rcx, rdx
|
||||||
|
mov dx, di
|
||||||
|
rep outsw
|
||||||
|
ret
|
||||||
|
|
||||||
|
global insw
|
||||||
|
insw:
|
||||||
|
mov rcx, rdx
|
||||||
|
mov dx, di
|
||||||
|
mov rdi, rsi
|
||||||
|
rep insw
|
||||||
|
ret
|
||||||
|
|
|
||||||
|
|
@ -34,3 +34,8 @@ uint32_t end_swap_u32(uint32_t value);
|
||||||
//4. zeroes rest of new buffer
|
//4. zeroes rest of new buffer
|
||||||
//5. sets buffer and length to new buffer and twice length
|
//5. sets buffer and length to new buffer and twice length
|
||||||
void double_buffer_zero(void **buffer, int *length, uint64_t bytes_per_entry);
|
void double_buffer_zero(void **buffer, int *length, uint64_t bytes_per_entry);
|
||||||
|
|
||||||
|
void outb(uint16_t port, uint8_t byte);
|
||||||
|
uint8_t inb(uint16_t port);
|
||||||
|
void outsw(uint16_t port, const void *buffer, uint64_t words);
|
||||||
|
void insw(uint16_t port, void *buffer, uint64_t words);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue