Skip to content

Commit 0ba18c0

Browse files
committed
Continue AHCI driver
1 parent d277645 commit 0ba18c0

File tree

4 files changed

+386
-8
lines changed

4 files changed

+386
-8
lines changed

applications/ahcidriver/src/ahcidriver.cpp

Lines changed: 307 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,47 @@
2020

2121
#include "ahcidriver.hpp"
2222
#include <cstdio>
23+
#include <cstring>
2324
#include <libahci/ahci.hpp>
25+
#include <libahci/ata.hpp>
2426
#include <libahci/driver.hpp>
2527
#include <libpci/driver.hpp>
2628

2729
static uint32_t controllerBar;
2830
static uint8_t controllerIntrLine;
2931

32+
void debugDumpBytes(const uint8_t* data, size_t len)
33+
{
34+
for(size_t i = 0; i < len; i += 64)
35+
{
36+
size_t chunk = (len - i >= 64) ? 64 : (len - i);
37+
char chars[64];
38+
39+
for(size_t j = 0; j < chunk; j++)
40+
{
41+
uint8_t b = data[i + j];
42+
chars[j] = (b == 0) ? '0' : (char) b;
43+
}
44+
for(size_t j = chunk; j < 64; j++)
45+
{
46+
chars[j] = ' ';
47+
}
48+
49+
klog(
50+
"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c"
51+
"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
52+
chars[0], chars[1], chars[2], chars[3], chars[4], chars[5], chars[6], chars[7],
53+
chars[8], chars[9], chars[10], chars[11], chars[12], chars[13], chars[14], chars[15],
54+
chars[16], chars[17], chars[18], chars[19], chars[20], chars[21], chars[22], chars[23],
55+
chars[24], chars[25], chars[26], chars[27], chars[28], chars[29], chars[30], chars[31],
56+
chars[32], chars[33], chars[34], chars[35], chars[36], chars[37], chars[38], chars[39],
57+
chars[40], chars[41], chars[42], chars[43], chars[44], chars[45], chars[46], chars[47],
58+
chars[48], chars[49], chars[50], chars[51], chars[52], chars[53], chars[54], chars[55],
59+
chars[56], chars[57], chars[58], chars[59], chars[60], chars[61], chars[62], chars[63]
60+
);
61+
}
62+
}
63+
3064
int main()
3165
{
3266
if(!g_task_register_name(G_AHCI_DRIVER_NAME))
@@ -56,7 +90,30 @@ int main()
5690
{
5791
if(!(ahciGhc->pi & (1 << portNumber)))
5892
continue;
59-
ahciIdentifyDevice(portNumber, &ahciPorts[portNumber]);
93+
94+
g_ahci_device* ahciDevice = nullptr;
95+
if(!ahciInitializeDevice(portNumber, &ahciPorts[portNumber], &ahciDevice))
96+
{
97+
klog("AHCI device initialization on port %i failed", portNumber);
98+
continue;
99+
}
100+
101+
if(!ahciIdentifyDevice(ahciDevice))
102+
{
103+
klog("AHCI device identification on port %i failed", portNumber);
104+
continue;
105+
}
106+
107+
// Try to read something
108+
void* outVirt;
109+
if(!ahciReadDMA(ahciDevice, 0, 1, &outVirt))
110+
{
111+
klog("failed to read from AHCI device on port %i", portNumber);
112+
continue;
113+
}
114+
klog("SUCCESSFULLY READ DATA!");
115+
116+
debugDumpBytes((uint8_t*) outVirt, 512);
60117
}
61118

62119
g_sleep(999999);
@@ -106,28 +163,271 @@ bool ahciDriverIdentifyController()
106163
}
107164

108165

109-
void ahciIdentifyDevice(uint8_t portNumber, volatile g_ahci_hba_port* port)
166+
void ahciPrintDeviceData(identify_device_response_t* id_data)
167+
{
168+
char model[41];
169+
memset(model, 0, sizeof(model));
170+
for(int i = 0; i < 20; i++)
171+
{
172+
model[i * 2] = (id_data->ModelNumber[i] >> 8) & 0xFF;
173+
model[i * 2 + 1] = id_data->ModelNumber[i] & 0xFF;
174+
}
175+
176+
char serial[21];
177+
memset(serial, 0, sizeof(serial));
178+
for(int i = 0; i < 10; i++)
179+
{
180+
serial[i * 2] = (id_data->SerialNumber[i] >> 8) & 0xFF;
181+
serial[i * 2 + 1] = id_data->SerialNumber[i] & 0xFF;
182+
}
183+
184+
char firmware[5];
185+
memset(firmware, 0, sizeof(firmware));
186+
for(int i = 0; i < 4; i++)
187+
{
188+
firmware[i] = (id_data->FirmwareRevision[i] >> 8) & 0xFF;
189+
firmware[i + 1] = id_data->FirmwareRevision[i] & 0xFF;
190+
}
191+
192+
klog("model: \"%s\"", model);
193+
klog("serial number: \"%s\"", serial);
194+
klog("firmware revision: \"%s\"", firmware);
195+
klog("heads: %i", id_data->Heads);
196+
klog("cylinders: %i", id_data->CylindersLow);
197+
klog("sectors per track: %i", id_data->SectorsPerTrack);
198+
}
199+
200+
bool ahciReadDMA(g_ahci_device* ahciDevice,
201+
uint64_t lba,
202+
uint16_t sectorCount,
203+
void** outVirt)
204+
{
205+
int slot = ahciFindFreeCommandSlot(ahciDevice->port);
206+
if(slot == -1)
207+
return false;
208+
209+
size_t bytes = (size_t) sectorCount * 512;
210+
if(bytes > G_PAGE_SIZE)
211+
{
212+
// TODO
213+
klog("TODO: FAILED TO READ DMA - no contiugous physical alloc implemneted");
214+
return false;
215+
}
216+
217+
size_t alloc_size = ((bytes + G_PAGE_SIZE - 1) / G_PAGE_SIZE) * G_PAGE_SIZE;
218+
void* data_phys;
219+
void* data_virt = g_alloc_mem_p(alloc_size, &data_phys);
220+
if(!data_phys)
221+
return false;
222+
memset(data_virt, 0, alloc_size);
223+
224+
void* cmdTablePhys;
225+
void* cmdTable = g_alloc_mem_p(G_PAGE_SIZE, &cmdTablePhys);
226+
if(!cmdTablePhys)
227+
{
228+
klog("failed to allocate buffer for cmd table");
229+
return false;
230+
}
231+
memset(cmdTable, 0, G_PAGE_SIZE);
232+
233+
auto cmd = &ahciDevice->cmdList.mapped[slot];
234+
memset((void*) cmd, 0, sizeof(*cmd));
235+
236+
auto prdts = (g_hba_prdt_entry*) (cmdTable + G_HBA_COMMAND_TABLE_PRDT_OFFSET);
237+
prdts[0].dba = ((uint64_t) data_phys) & 0xFFFFFFFFUL;
238+
prdts[0].dbau = ((uint64_t) data_phys >> 32) & 0xFFFFFFFFUL;
239+
prdts[0].dbc = (uint32_t) (bytes - 1);
240+
prdts[0].i = 1;
241+
242+
cmd->prdtl = 1;
243+
cmd->ctba = ((uint64_t) cmdTablePhys) & 0xFFFFFFFFUL;
244+
cmd->ctbau = ((uint64_t) cmdTablePhys >> 32) & 0xFFFFFFFFUL;
245+
cmd->cfl = sizeof(g_fis_reg_h2d) / sizeof(uint32_t);
246+
cmd->w = 0; // read
247+
248+
auto cmdFis = (g_fis_reg_h2d*) &((g_hba_command_table*) cmdTable)->cfis;
249+
memset(cmdFis, 0, sizeof(*cmdFis));
250+
cmdFis->type = G_FIS_TYPE_REG_H2D;
251+
cmdFis->c = 1;
252+
cmdFis->command = 0x25; // read dma ext
253+
cmdFis->device = 0x40; // lba mode
254+
255+
cmdFis->lba0 = (uint8_t) (lba & 0xFF);
256+
cmdFis->lba1 = (uint8_t) ((lba >> 8) & 0xFF);
257+
cmdFis->lba2 = (uint8_t) ((lba >> 16) & 0xFF);
258+
cmdFis->lba3 = (uint8_t) ((lba >> 24) & 0xFF);
259+
cmdFis->lba4 = (uint8_t) ((lba >> 32) & 0xFF);
260+
cmdFis->lba5 = (uint8_t) ((lba >> 40) & 0xFF);
261+
262+
cmdFis->countL = (uint8_t) (sectorCount & 0xFF);
263+
cmdFis->countH = (uint8_t) ((sectorCount >> 8) & 0xFF);
264+
265+
ahciDevice->port->is = -1;
266+
ahciDevice->port->ie = 1;
267+
268+
while(ahciDevice->port->tfd & (0x80 | 0x08))
269+
g_sleep(1);
270+
271+
ahciDevice->port->ci = 1 << slot;
272+
273+
while(ahciDevice->port->ci & (1 << slot))
274+
{
275+
if(ahciDevice->port->is & (1 << 30))
276+
{
277+
klog("ahci: task file error on port");
278+
return false;
279+
}
280+
g_sleep(1);
281+
}
282+
283+
if(outVirt)
284+
*outVirt = data_virt;
285+
return true;
286+
}
287+
288+
289+
bool ahciInitializeDevice(uint8_t portNumber, volatile g_ahci_hba_port* port, g_ahci_device** outAhciDevice)
110290
{
111291
if(!(port->ssts.det == G_AHCI_HBA_PORT_SSTS_DET_READY))
112292
{
113293
klog("device on port %i not present or ready: %i", portNumber, port->ssts.det);
114-
return;
294+
return false;
115295
}
116296

117297
if(port->sig != G_SATA_SIGNATURE_ATA)
118298
{
119299
klog("port %i does not have an ATA device: %x", portNumber, port->sig);
120-
return;
300+
return false;
121301
}
122302

123303
if(!ahciPortStopCommands(port))
124304
{
125305
klog("timed out when trying to stop commands on port %i", portNumber);
126-
return;
306+
return false;
307+
}
308+
309+
// Initialize command list
310+
void* cmdListPhys;
311+
void* cmdList = g_alloc_mem_p(G_PAGE_SIZE, &cmdListPhys);
312+
if(!cmdListPhys)
313+
{
314+
klog("failed to allocate physical memory for command-list of device");
315+
return false;
316+
}
317+
port->clb = ((uint64_t) cmdListPhys) & 0xFFFFFFFFUL;
318+
port->clbu = ((uint64_t) cmdListPhys >> 32) & 0xFFFFFFFFUL;
319+
memset(cmdList, 0, G_PAGE_SIZE);
320+
321+
// Initialize FIS memory
322+
void* fisPhys;
323+
void* fis = g_alloc_mem_p(G_PAGE_SIZE, &fisPhys);
324+
if(!fisPhys)
325+
{
326+
klog("failed to allocate physical memory for FIS of device");
327+
return false;
328+
}
329+
memset(fis, 0, G_PAGE_SIZE);
330+
port->fb = ((uint64_t) fisPhys) & 0xFFFFFFFFUL;;
331+
port->fbu = ((uint64_t) fisPhys >> 32) & 0xFFFFFFFFUL;
332+
333+
// Start commands
334+
if(!ahciPortStartCommands(port))
335+
{
336+
klog("failed to start AHCI commands on port %i", port);
337+
return false;
338+
}
339+
340+
// Clear pending interrupt bits
341+
port->is = -1;
342+
port->ie = 1;
343+
344+
// Create device
345+
auto ahciDevice = new g_ahci_device();
346+
ahciDevice->portNumber = portNumber;
347+
ahciDevice->port = port;
348+
ahciDevice->cmdList.mapped = (g_hba_command_header*) cmdList;
349+
ahciDevice->cmdList.physical = cmdListPhys;
350+
ahciDevice->fis.mapped = fis;
351+
ahciDevice->fis.physical = fisPhys;
352+
*outAhciDevice = ahciDevice;
353+
354+
return true;
355+
}
356+
357+
358+
bool ahciIdentifyDevice(g_ahci_device* ahciDevice)
359+
{
360+
int slot = ahciFindFreeCommandSlot(ahciDevice->port);
361+
if(slot == -1)
362+
{
363+
klog("failed to find free slot to issue identify-device command");
364+
return false;
365+
}
366+
367+
// Buffer for command result
368+
void* outPhys;
369+
void* out = g_alloc_mem_p(G_PAGE_SIZE, &outPhys);
370+
if(!outPhys)
371+
{
372+
klog("failed to allocate buffer for command output");
373+
return false;
374+
}
375+
memset(out, 0, G_PAGE_SIZE);
376+
377+
// Buffer for cmd table
378+
void* cmdTablePhys;
379+
void* cmdTable = g_alloc_mem_p(G_PAGE_SIZE, &cmdTablePhys);
380+
if(!cmdTablePhys)
381+
{
382+
klog("failed to allocate buffer for cmd table");
383+
return false;
384+
}
385+
memset(cmdTable, 0, G_PAGE_SIZE);
386+
387+
// Create command
388+
auto cmd = &ahciDevice->cmdList.mapped[slot];
389+
cmd->prdtl = 1;
390+
cmd->cfl = sizeof(g_fis_reg_h2d) / sizeof(uint32_t);
391+
cmd->w = 0;
392+
393+
cmd->ctba = ((uint64_t) cmdTablePhys) & 0xFFFFFFFFUL;
394+
cmd->ctbau = ((uint64_t) cmdTablePhys >> 32) & 0xFFFFFFFFUL;
395+
396+
// CMD table
397+
auto prdts = (g_hba_prdt_entry*) (cmdTable + G_HBA_COMMAND_TABLE_PRDT_OFFSET);
398+
prdts[0].dba = ((uint64_t) outPhys) & 0xFFFFFFFFUL;
399+
prdts[0].dbau = ((uint64_t) outPhys >> 32) & 0xFFFFFFFFUL;
400+
prdts[0].dbc = (512 - 1);
401+
prdts[0].i = 1;
402+
403+
// Fill the FIS
404+
auto cmdFis = (g_fis_reg_h2d*) &((g_hba_command_table*) cmdTable)->cfis;
405+
cmdFis->type = G_FIS_TYPE_REG_H2D;
406+
cmdFis->command = 0xEC; // ATA Identify Device
407+
cmdFis->device = 0; // Master Device
408+
cmdFis->c = 1;
409+
410+
// Wait for device to be ready
411+
while((ahciDevice->port->tfd & (0x80 /* ATA_DEV_BUSY */ | 0x08 /* ATA_DEV_DRQ */)))
412+
g_sleep(1);
413+
414+
// Issue command in slot
415+
ahciDevice->port->ci = 1 << slot;
416+
417+
// Wait for completion
418+
while(ahciDevice->port->ci & (1 << slot))
419+
{
420+
if(ahciDevice->port->is & (1 << 30))
421+
{
422+
// TODO Handle error
423+
klog("task file error");
424+
return false;
425+
}
426+
g_sleep(1);
127427
}
128428

129-
// ...
130-
klog("ready to initialize device on port %i", portNumber);
429+
ahciPrintDeviceData((identify_device_response_t*) out);
430+
return true;
131431
}
132432

133433
bool ahciPortStartCommands(volatile g_ahci_hba_port* port)

applications/ahcidriver/src/ahcidriver.hpp

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,32 @@
2525
#include <ghost.h>
2626
#include <libahci/ahci.hpp>
2727

28+
struct g_ahci_device
29+
{
30+
uint8_t portNumber;
31+
volatile g_ahci_hba_port* port;
32+
33+
struct
34+
{
35+
volatile g_hba_command_header* mapped;
36+
void* physical;
37+
} cmdList;
38+
39+
struct
40+
{
41+
void* mapped;
42+
void* physical;
43+
} fis;
44+
};
45+
2846
bool ahciDriverIdentifyController();
2947
bool ahciPortStartCommands(volatile g_ahci_hba_port* port);
3048
bool ahciPortStopCommands(volatile g_ahci_hba_port* port);
3149
int ahciFindFreeCommandSlot(volatile g_ahci_hba_port* port);
32-
void ahciIdentifyDevice(uint8_t portNumber, volatile g_ahci_hba_port* port);
50+
51+
bool ahciInitializeDevice(uint8_t portNumber, volatile g_ahci_hba_port* port, g_ahci_device** outAhciDevice);
52+
bool ahciIdentifyDevice(g_ahci_device* ahciDevice);
53+
bool ahciReadDMA(g_ahci_device* ahciDevice, uint64_t lba, uint16_t sectorCount, void** outVirt);
54+
3355

3456
#endif

0 commit comments

Comments
 (0)