mirror of
https://github.com/wichtounet/thor-os.git
synced 2025-09-11 05:24:44 -04:00
Start reading the disk
This commit is contained in:
parent
0089179eda
commit
71e33e3a8b
@ -14,6 +14,12 @@
|
|||||||
#include "kernel.hpp"
|
#include "kernel.hpp"
|
||||||
#include "early_memory.hpp"
|
#include "early_memory.hpp"
|
||||||
#include "virtual_debug.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 {
|
namespace {
|
||||||
|
|
||||||
@ -31,15 +37,34 @@ void early_log(const char* s){
|
|||||||
early::early_logs_count(c + 1);
|
early::early_logs_count(c + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef unsigned int uint8_t __attribute__((__mode__(__QI__)));
|
void virtual_debug(const uint32_t& value){
|
||||||
typedef unsigned int uint16_t __attribute__ ((__mode__ (__HI__)));
|
char buffer[32];
|
||||||
typedef unsigned int uint32_t __attribute__ ((__mode__ (__SI__)));
|
|
||||||
typedef unsigned int uint64_t __attribute__ ((__mode__ (__DI__)));
|
|
||||||
|
|
||||||
static_assert(sizeof(uint8_t) == 1, "uint8_t must be 1 byte long");
|
if(value == 0){
|
||||||
static_assert(sizeof(uint16_t) == 2, "uint16_t must be 2 bytes long");
|
::virtual_debug("0");
|
||||||
static_assert(sizeof(uint32_t) == 4, "uint32_t must be 4 bytes long");
|
return;
|
||||||
static_assert(sizeof(uint64_t) == 8, "uint64_t must be 8 bytes long");
|
}
|
||||||
|
|
||||||
|
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;
|
const uint32_t PML4T = 0x70000;
|
||||||
|
|
||||||
@ -145,6 +170,139 @@ void serial_init() {
|
|||||||
out_byte(COM1_PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
|
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
|
} //end of anonymous namespace
|
||||||
|
|
||||||
bool serial_is_transmit_buffer_empty() {
|
bool serial_is_transmit_buffer_empty() {
|
||||||
@ -184,6 +342,8 @@ void pm_main(){
|
|||||||
//Enable paging
|
//Enable paging
|
||||||
enable_paging();
|
enable_paging();
|
||||||
|
|
||||||
|
detect_disks();
|
||||||
|
|
||||||
asm volatile("cli; hlt");
|
asm volatile("cli; hlt");
|
||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
|
|
||||||
|
@ -28,8 +28,6 @@ inline void out_byte (uint16_t _port, uint8_t _data){
|
|||||||
: [port] "dN" (_port), [data] "a" (_data));
|
: [port] "dN" (_port), [data] "a" (_data));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef THOR_INIT
|
|
||||||
|
|
||||||
inline uint16_t in_word(uint16_t _port){
|
inline uint16_t in_word(uint16_t _port){
|
||||||
uint16_t rv;
|
uint16_t rv;
|
||||||
|
|
||||||
@ -40,6 +38,14 @@ inline uint16_t in_word(uint16_t _port){
|
|||||||
return rv;
|
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){
|
inline uint32_t in_dword(uint16_t _port){
|
||||||
uint32_t rv;
|
uint32_t rv;
|
||||||
|
|
||||||
@ -60,12 +66,6 @@ inline uint64_t in_qword(uint16_t _port){
|
|||||||
return rv;
|
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){
|
inline void out_dword(uint16_t _port, uint32_t _data){
|
||||||
asm volatile ("out %[port], %[data]"
|
asm volatile ("out %[port], %[data]"
|
||||||
: /* No outputs */
|
: /* No outputs */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user