mirror of
https://github.com/wichtounet/thor-os.git
synced 2025-09-09 20:43:34 -04:00
Start reading the disk
This commit is contained in:
parent
0089179eda
commit
71e33e3a8b
@ -14,6 +14,12 @@
|
||||
#include "kernel.hpp"
|
||||
#include "early_memory.hpp"
|
||||
#include "virtual_debug.hpp"
|
||||
#include "ata_constants.hpp"
|
||||
|
||||
static_assert(sizeof(uint8_t) == 1, "uint8_t must be 1 byte long");
|
||||
static_assert(sizeof(uint16_t) == 2, "uint16_t must be 2 bytes long");
|
||||
static_assert(sizeof(uint32_t) == 4, "uint32_t must be 4 bytes long");
|
||||
static_assert(sizeof(uint64_t) == 8, "uint64_t must be 8 bytes long");
|
||||
|
||||
namespace {
|
||||
|
||||
@ -31,15 +37,34 @@ void early_log(const char* s){
|
||||
early::early_logs_count(c + 1);
|
||||
}
|
||||
|
||||
typedef unsigned int uint8_t __attribute__((__mode__(__QI__)));
|
||||
typedef unsigned int uint16_t __attribute__ ((__mode__ (__HI__)));
|
||||
typedef unsigned int uint32_t __attribute__ ((__mode__ (__SI__)));
|
||||
typedef unsigned int uint64_t __attribute__ ((__mode__ (__DI__)));
|
||||
void virtual_debug(const uint32_t& value){
|
||||
char buffer[32];
|
||||
|
||||
static_assert(sizeof(uint8_t) == 1, "uint8_t must be 1 byte long");
|
||||
static_assert(sizeof(uint16_t) == 2, "uint16_t must be 2 bytes long");
|
||||
static_assert(sizeof(uint32_t) == 4, "uint32_t must be 4 bytes long");
|
||||
static_assert(sizeof(uint64_t) == 8, "uint64_t must be 8 bytes long");
|
||||
if(value == 0){
|
||||
::virtual_debug("0");
|
||||
return;
|
||||
}
|
||||
|
||||
char int_buffer[20];
|
||||
int i = 0;
|
||||
auto rem = value;
|
||||
|
||||
while(rem != 0){
|
||||
int_buffer[i++] = '0' + rem % 10;
|
||||
rem /= 10;
|
||||
}
|
||||
|
||||
--i;
|
||||
|
||||
size_t j = 0;
|
||||
for(; i >= 0; --i){
|
||||
buffer[j++] = int_buffer[i];
|
||||
}
|
||||
|
||||
buffer[j] = '\0';
|
||||
|
||||
::virtual_debug(buffer);
|
||||
}
|
||||
|
||||
const uint32_t PML4T = 0x70000;
|
||||
|
||||
@ -145,6 +170,139 @@ void serial_init() {
|
||||
out_byte(COM1_PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
|
||||
}
|
||||
|
||||
inline void ata_400ns_delay(uint16_t controller){
|
||||
in_byte(controller + ATA_STATUS);
|
||||
in_byte(controller + ATA_STATUS);
|
||||
in_byte(controller + ATA_STATUS);
|
||||
in_byte(controller + ATA_STATUS);
|
||||
in_byte(controller + ATA_STATUS);
|
||||
in_byte(controller + ATA_STATUS);
|
||||
in_byte(controller + ATA_STATUS);
|
||||
in_byte(controller + ATA_STATUS);
|
||||
in_byte(controller + ATA_STATUS);
|
||||
}
|
||||
|
||||
uint8_t wait_for_controller(uint16_t controller, uint8_t mask, uint8_t value, uint16_t timeout){
|
||||
uint8_t status;
|
||||
do {
|
||||
// Sleep at least 400ns before reading the status register
|
||||
ata_400ns_delay(controller);
|
||||
|
||||
// Final read of the controller status
|
||||
status = in_byte(controller + ATA_STATUS);
|
||||
} while ((status & mask) != value && --timeout);
|
||||
|
||||
return timeout;
|
||||
}
|
||||
|
||||
bool ata_select_device(){
|
||||
auto wait_mask = ATA_STATUS_BSY | ATA_STATUS_DRQ;
|
||||
|
||||
if(!wait_for_controller(ATA_PRIMARY, wait_mask, 0, 10000)){
|
||||
return false;
|
||||
}
|
||||
|
||||
//Indicate the selected device
|
||||
out_byte(ATA_PRIMARY + ATA_DRV_HEAD, 0xA0 | (MASTER_BIT << 4));
|
||||
|
||||
if(!wait_for_controller(ATA_PRIMARY, wait_mask, 0, 10000)){
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool read_sector(uint64_t start, void* data){
|
||||
//Select the device
|
||||
if(!ata_select_device()){
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t sc = start & 0xFF;
|
||||
uint8_t cl = (start >> 8) & 0xFF;
|
||||
uint8_t ch = (start >> 16) & 0xFF;
|
||||
uint8_t hd = (start >> 24) & 0x0F;
|
||||
|
||||
//Process the command
|
||||
out_byte(ATA_PRIMARY + ATA_NSECTOR, 1);
|
||||
out_byte(ATA_PRIMARY + ATA_SECTOR, sc);
|
||||
out_byte(ATA_PRIMARY + ATA_LCYL, cl);
|
||||
out_byte(ATA_PRIMARY + ATA_HCYL, ch);
|
||||
out_byte(ATA_PRIMARY + ATA_DRV_HEAD, (1 << 6) | (MASTER_BIT << 4) | hd);
|
||||
out_byte(ATA_PRIMARY + ATA_COMMAND, ATA_READ_BLOCK);
|
||||
|
||||
//Wait at most 30 seconds for BSY flag to be cleared
|
||||
if(!wait_for_controller(ATA_PRIMARY, ATA_STATUS_BSY, 0, 30000)){
|
||||
return false;
|
||||
}
|
||||
|
||||
//Verify if there are errors
|
||||
if(in_byte(ATA_PRIMARY + ATA_STATUS) & ATA_STATUS_ERR){
|
||||
return false;
|
||||
}
|
||||
|
||||
// Polling
|
||||
|
||||
while(true){
|
||||
ata_400ns_delay(ATA_PRIMARY);
|
||||
|
||||
auto status = in_byte(ATA_PRIMARY + ATA_STATUS);
|
||||
|
||||
if(status & ATA_STATUS_BSY){
|
||||
continue;
|
||||
}
|
||||
|
||||
if(status & ATA_STATUS_ERR || status & ATA_STATUS_DF){
|
||||
return false;
|
||||
}
|
||||
|
||||
if(status & ATA_STATUS_DRQ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Read the disk sectors
|
||||
uint16_t* buffer = reinterpret_cast<uint16_t*>(data);
|
||||
for(int i = 0; i < 256; ++i){
|
||||
*buffer++ = in_word(ATA_PRIMARY + ATA_DATA);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void suspend_init(const char* message){
|
||||
early_log(message);
|
||||
asm volatile("cli; hlt");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void detect_disks(){
|
||||
// Disable all interrupts
|
||||
out_byte(ATA_PRIMARY + ATA_DEV_CTL, ATA_CTL_nIEN);
|
||||
out_byte(ATA_SECONDARY + ATA_DEV_CTL, ATA_CTL_nIEN);
|
||||
|
||||
// Make sure the primary controller is enabled
|
||||
|
||||
out_byte(ATA_PRIMARY + ATA_NSECTOR, 0xAB);
|
||||
if(in_byte(ATA_PRIMARY + ATA_NSECTOR) != 0xAB){
|
||||
suspend_init("The primary ATA controller is not enabled");
|
||||
}
|
||||
|
||||
char block_buffer[512];
|
||||
|
||||
// Read the MBR
|
||||
if(!read_sector(0, block_buffer)){
|
||||
suspend_init("Unable to read MBR");
|
||||
}
|
||||
|
||||
// Extract the start of the partition
|
||||
uint16_t partition_start = *reinterpret_cast<uint16_t*>(block_buffer + 0x1be);
|
||||
|
||||
// Reset interrupt status
|
||||
out_byte(ATA_PRIMARY + ATA_DEV_CTL, 0);
|
||||
out_byte(ATA_SECONDARY + ATA_DEV_CTL, 0);
|
||||
}
|
||||
|
||||
} //end of anonymous namespace
|
||||
|
||||
bool serial_is_transmit_buffer_empty() {
|
||||
@ -184,6 +342,8 @@ void pm_main(){
|
||||
//Enable paging
|
||||
enable_paging();
|
||||
|
||||
detect_disks();
|
||||
|
||||
asm volatile("cli; hlt");
|
||||
__builtin_unreachable();
|
||||
|
||||
|
@ -28,8 +28,6 @@ inline void out_byte (uint16_t _port, uint8_t _data){
|
||||
: [port] "dN" (_port), [data] "a" (_data));
|
||||
}
|
||||
|
||||
#ifndef THOR_INIT
|
||||
|
||||
inline uint16_t in_word(uint16_t _port){
|
||||
uint16_t rv;
|
||||
|
||||
@ -40,6 +38,14 @@ inline uint16_t in_word(uint16_t _port){
|
||||
return rv;
|
||||
}
|
||||
|
||||
inline void out_word(uint16_t _port, uint16_t _data){
|
||||
asm volatile ("out %[port], %[data]"
|
||||
: /* No outputs */
|
||||
: [port] "dN" (_port), [data] "a" (_data));
|
||||
}
|
||||
|
||||
#ifndef THOR_INIT
|
||||
|
||||
inline uint32_t in_dword(uint16_t _port){
|
||||
uint32_t rv;
|
||||
|
||||
@ -60,12 +66,6 @@ inline uint64_t in_qword(uint16_t _port){
|
||||
return rv;
|
||||
}
|
||||
|
||||
inline void out_word(uint16_t _port, uint16_t _data){
|
||||
asm volatile ("out %[port], %[data]"
|
||||
: /* No outputs */
|
||||
: [port] "dN" (_port), [data] "a" (_data));
|
||||
}
|
||||
|
||||
inline void out_dword(uint16_t _port, uint32_t _data){
|
||||
asm volatile ("out %[port], %[data]"
|
||||
: /* No outputs */
|
||||
|
Loading…
x
Reference in New Issue
Block a user