identify patapi drives
This commit is contained in:
parent
f409903f55
commit
fc79e09922
8 changed files with 425 additions and 1 deletions
48
src/kernel/drives.c
Normal file
48
src/kernel/drives.c
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
/* Calcite, src/kernel/drives.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 "utility.h"
|
||||||
|
#include "drives.h"
|
||||||
|
#include "heap.h"
|
||||||
|
|
||||||
|
struct drive_info *drive_list;
|
||||||
|
int drive_list_buffer_length = 0;
|
||||||
|
int drive_list_count = 0;
|
||||||
|
|
||||||
|
#define DRIVE_LIST_INITIAL_LENGTH 16
|
||||||
|
|
||||||
|
struct drive_info *add_drive() {
|
||||||
|
|
||||||
|
if (drive_list_buffer_length == 0) {
|
||||||
|
drive_list = heap_alloc(DRIVE_LIST_INITIAL_LENGTH * sizeof(struct drive_info));
|
||||||
|
drive_list_buffer_length = DRIVE_LIST_INITIAL_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (drive_list_count == drive_list_buffer_length) {
|
||||||
|
struct drive_info *new_drive_list =
|
||||||
|
heap_alloc(2 * drive_list_buffer_length * sizeof(struct drive_info));
|
||||||
|
memcpy(new_drive_list, drive_list, drive_list_count * sizeof(struct drive_info));
|
||||||
|
heap_dealloc(drive_list, drive_list_count * sizeof(struct drive_info));
|
||||||
|
drive_list = new_drive_list;
|
||||||
|
drive_list_buffer_length *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct drive_info *to_return = &drive_list[drive_list_count];
|
||||||
|
++drive_list_count;
|
||||||
|
return to_return;
|
||||||
|
|
||||||
|
}
|
||||||
43
src/kernel/drives.h
Normal file
43
src/kernel/drives.h
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
/* Calcite, src/kernel/drives.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>
|
||||||
|
|
||||||
|
enum drive_access_result {
|
||||||
|
DAR_SUCCESS
|
||||||
|
};
|
||||||
|
|
||||||
|
struct drive_info {
|
||||||
|
|
||||||
|
const char *name;
|
||||||
|
uint64_t block_size;
|
||||||
|
uint64_t block_count;
|
||||||
|
const void *driver_info;
|
||||||
|
|
||||||
|
//start and count are both in blocks
|
||||||
|
enum drive_access_result (*read_blocks)(
|
||||||
|
const void *driver_info, void *buffer, uint64_t start, uint64_t count);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
//add a drive by calling this and writing to the returned pointer.
|
||||||
|
//the returned pointer might be invalidated by future calls.
|
||||||
|
struct drive_info *add_drive();
|
||||||
|
|
||||||
|
const struct drive_info *look_up_drive(const char *name);
|
||||||
|
|
@ -15,9 +15,9 @@
|
||||||
* with this program. If not, see <https://www.gnu.org/licenses/>.
|
* with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "kernel-public/syscall-numbers.h"
|
||||||
#include "framebuffer.h"
|
#include "framebuffer.h"
|
||||||
#include "interrupts.h"
|
#include "interrupts.h"
|
||||||
#include "kernel-public/syscall-numbers.h"
|
|
||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
#include "syscalls.h"
|
#include "syscalls.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
#include "paging.h"
|
#include "paging.h"
|
||||||
#include "panic.h"
|
#include "panic.h"
|
||||||
#include "heap.h"
|
#include "heap.h"
|
||||||
|
#include "pata.h"
|
||||||
#include "ps2.h"
|
#include "ps2.h"
|
||||||
|
|
||||||
#include <limine.h>
|
#include <limine.h>
|
||||||
|
|
@ -198,6 +199,10 @@ static uint64_t initfs_length;
|
||||||
register_syscall(SYSCALL_END_THREAD, (void *)&syscall_end_thread);
|
register_syscall(SYSCALL_END_THREAD, (void *)&syscall_end_thread);
|
||||||
register_syscall(SYSCALL_MAP_FRAMEBUFFER, (void *)&syscall_map_framebuffer);
|
register_syscall(SYSCALL_MAP_FRAMEBUFFER, (void *)&syscall_map_framebuffer);
|
||||||
|
|
||||||
|
//probe for drives
|
||||||
|
|
||||||
|
probe_pata_drives();
|
||||||
|
|
||||||
//load hello and start it
|
//load hello and start it
|
||||||
|
|
||||||
init_scheduler();
|
init_scheduler();
|
||||||
|
|
|
||||||
129
src/kernel/pata.asm
Normal file
129
src/kernel/pata.asm
Normal file
|
|
@ -0,0 +1,129 @@
|
||||||
|
; 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
|
||||||
|
|
||||||
|
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
|
||||||
165
src/kernel/pata.c
Normal file
165
src/kernel/pata.c
Normal file
|
|
@ -0,0 +1,165 @@
|
||||||
|
/* Calcite, src/kernel/pata.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 "utility.h"
|
||||||
|
#include "drives.h"
|
||||||
|
#include "panic.h"
|
||||||
|
#include "heap.h"
|
||||||
|
#include "pata.h"
|
||||||
|
|
||||||
|
//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 {
|
||||||
|
PR_SUCCESS,
|
||||||
|
PR_NO_CONTROLLER,
|
||||||
|
PR_ABORTED
|
||||||
|
};
|
||||||
|
|
||||||
|
enum pata_result wait_pio(uint8_t controller) {
|
||||||
|
while (1) {
|
||||||
|
uint8_t status = pata_read_status(controller);
|
||||||
|
//0x00 happens in qemu, 0x7f happens in virtualbox
|
||||||
|
if (status == 0x00 || status == 0x7f)
|
||||||
|
return PR_NO_CONTROLLER;
|
||||||
|
if (status & 0x01) {
|
||||||
|
uint8_t error = pata_read_error(controller);
|
||||||
|
if (error == 0x04)
|
||||||
|
return PR_ABORTED;
|
||||||
|
panic("TODO")
|
||||||
|
}
|
||||||
|
if ((status & 0x80) || !(status & 0x08))
|
||||||
|
continue;
|
||||||
|
return PR_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//buffer should have room for 256 words.
|
||||||
|
static enum pata_result
|
||||||
|
pata_identify_packet_device(uint8_t drive, uint16_t *buffer) {
|
||||||
|
|
||||||
|
uint8_t controller = drive >> 1;
|
||||||
|
|
||||||
|
pata_set_device(controller, (drive & 0x01) << 4);
|
||||||
|
pata_set_command(controller, 0xa1);
|
||||||
|
|
||||||
|
enum pata_result result = wait_pio(controller);
|
||||||
|
if (result != PR_SUCCESS)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
pata_read_data(controller, buffer, 256);
|
||||||
|
return PR_SUCCESS;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum pata_result patapi_read_capacity(
|
||||||
|
uint8_t drive, uint32_t *max_block_out, uint32_t *block_size_out) {
|
||||||
|
|
||||||
|
uint8_t controller = drive >> 1;
|
||||||
|
|
||||||
|
pata_set_device(controller, (drive & 0x01) << 4);
|
||||||
|
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)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
uint8_t cmd[12] = {
|
||||||
|
0x25, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0 };
|
||||||
|
pata_write_data(controller, (uint16_t *)cmd, 6);
|
||||||
|
|
||||||
|
result = wait_pio(controller);
|
||||||
|
if (result != PR_SUCCESS)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
uint32_t actual_response_size = pata_read_lba(controller) >> 8;
|
||||||
|
if (actual_response_size != 8)
|
||||||
|
panic("TODO")
|
||||||
|
|
||||||
|
uint32_t response[2];
|
||||||
|
pata_read_data(controller, (uint16_t *)response, 4);
|
||||||
|
|
||||||
|
*max_block_out = end_swap_u32(response[0]);
|
||||||
|
*block_size_out = end_swap_u32(response[1]);
|
||||||
|
return PR_SUCCESS;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t ipd_buffer[256];
|
||||||
|
|
||||||
|
struct pata_driver_info {
|
||||||
|
uint8_t drive;
|
||||||
|
};
|
||||||
|
|
||||||
|
static enum drive_access_result read_blocks_patapi(
|
||||||
|
const struct pata_driver_info *driver_info,
|
||||||
|
void *buffer, uint64_t start, uint64_t count) {
|
||||||
|
|
||||||
|
panic("TODO");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void probe_pata_drive(uint8_t drive) {
|
||||||
|
|
||||||
|
if (pata_identify_packet_device(drive, ipd_buffer) != PR_SUCCESS)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint32_t max_block, block_size;
|
||||||
|
if (patapi_read_capacity(drive, &max_block, &block_size) != PR_SUCCESS)
|
||||||
|
return;
|
||||||
|
|
||||||
|
struct drive_info *di = add_drive();
|
||||||
|
|
||||||
|
char *name = heap_alloc(6);
|
||||||
|
memcpy(name, "pata", 4);
|
||||||
|
name[4] = '0' + drive;
|
||||||
|
name[5] = 0;
|
||||||
|
di->name = name;
|
||||||
|
|
||||||
|
di->block_size = block_size;
|
||||||
|
di->block_count = max_block + 1;
|
||||||
|
|
||||||
|
struct pata_driver_info *driver_info =
|
||||||
|
heap_alloc(sizeof(struct pata_driver_info));
|
||||||
|
driver_info->drive = drive;
|
||||||
|
di->driver_info = driver_info;
|
||||||
|
|
||||||
|
di->read_blocks = (void *)&read_blocks_patapi;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void probe_pata_drives() {
|
||||||
|
for (int i = 0; i < 4; ++i)
|
||||||
|
probe_pata_drive(i);
|
||||||
|
}
|
||||||
23
src/kernel/pata.h
Normal file
23
src/kernel/pata.h
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
/* Calcite, src/kernel/pata.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>
|
||||||
|
|
||||||
|
//probes for all four pata drives and adds any that exist to drives.h
|
||||||
|
void probe_pata_drives();
|
||||||
|
|
@ -37,3 +37,11 @@ void memzero(void *start, uint64_t bytes) {
|
||||||
for (uint64_t i = 0; i < bytes; ++i)
|
for (uint64_t i = 0; i < bytes; ++i)
|
||||||
*(uint8_t *)(start + i) = 0;
|
*(uint8_t *)(start + i) = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t end_swap_u32(uint32_t value) {
|
||||||
|
return
|
||||||
|
(value >> 24) |
|
||||||
|
(((value >> 16) & 0xff) << 8) |
|
||||||
|
(((value >> 8) & 0xff) << 16) |
|
||||||
|
((value & 0xff) << 24);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,3 +24,6 @@ int strequ(const char *str1, const char *str2);
|
||||||
|
|
||||||
void memcpy(void *to, const void *from, uint64_t bytes);
|
void memcpy(void *to, const void *from, uint64_t bytes);
|
||||||
void memzero(void *start, uint64_t bytes);
|
void memzero(void *start, uint64_t bytes);
|
||||||
|
|
||||||
|
//swaps the endianness of the value
|
||||||
|
uint32_t end_swap_u32(uint32_t value);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue