Skip to content

Commit 22cb6d6

Browse files
author
tthomps
committed
Continue implementing IDE controller support. IDE driver can now show connected drives.
Add "ide" command to console shell to show connected drives. Add gif of GUI running and update README.md.
1 parent a5a976f commit 22cb6d6

File tree

9 files changed

+277
-34
lines changed

9 files changed

+277
-34
lines changed

Media/Screenshots/MyOS_GUI.gif

3.88 MB
Loading

My-Doom

MyOS_1/Build_Number.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
// Define a build number. This number will be incremented by a simple console program called by a post-build event
44
// It's put here in its own file to keep the other program from messing up the source
55
#define \
6-
BUILD_NUMBER 5943
6+
BUILD_NUMBER 6354

MyOS_1/Console_Shell.c

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "myos_io.h"
3131
#include "Drivers\Keyboard.h"
3232
#include "../MyOS_GUI_Shell/GUI_Kernel_Shell.h"
33+
#include "Drivers/IDE.h"
3334

3435
int inputPosition = 0;
3536
#define COMMAND_HISTORY_SIZE 10
@@ -425,6 +426,30 @@ void Shell_Process_command(void)
425426
return;
426427
}
427428

429+
// Display connected IDE drives
430+
if (strcmp(currentCommand, "ide") == 0)
431+
{
432+
kprintf("Attached IDE devices:");
433+
bool deviceFound = false;
434+
435+
for (uint8_t device = 0; device < 4; ++device)
436+
{
437+
if (ide_devices[device].Present)
438+
{
439+
deviceFound = true;
440+
kprintf("\n%s drive at Channel %d device %d - %s",
441+
ide_devices[device].Type == IDE_ATA ? " ATA" : " ATAPI",
442+
ide_devices[device].Channel,
443+
ide_devices[device].Drive,
444+
ide_devices[device].Model);
445+
}
446+
}
447+
448+
kprintf(deviceFound ? "\n" : " None\n");
449+
450+
return;
451+
}
452+
428453
// Initialize mouse
429454
if (strcmp(currentCommand, "m") == 0)
430455
{
@@ -944,9 +969,7 @@ void Shell_Process_command(void)
944969
return;
945970
}
946971

947-
// Temporary command to facilitate loading a program at a second memory address,
948-
// which will let us get multiprogramming working with two processes without having to worry about virtual memory for now
949-
// Runhi command
972+
// Runhi command - used to load GUI at a different memory address than other programs, mapped into kernel space
950973
memset(subCommand, 0, MAX_COMMAND_LENGTH);
951974
strncpy(subCommand, currentCommand, strlen("runhi"));
952975
if (strcmp(subCommand, "runhi") == 0)

MyOS_1/Drivers/IDE.c

Lines changed: 216 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,75 @@
11
#include "IDE.h"
22
#include "../printf.h"
33
#include "../System_Specific.h"
4+
#include "../Timers/System_Clock.h"
5+
#include "../misc.h"
6+
#include "../Interrupts/IDT.h"
7+
#include "../Interrupts/Interrupts.h"
8+
49
// TODO: Support multiple IDE controllers
510
uint8_t IDE_bus;
611
uint8_t IDE_slot;
712
uint8_t IDE_function;
813
bool IDE_Present;
914

10-
IDE_CHANNEL_REGISTERS channels[2];
15+
IDE_CHANNEL_INFO channels[2];
1116

1217
uint8_t ide_buf[2048] = { 0 };
1318
bool ide_irq_invoked = 0;
14-
uint8_t atapi_packet[12] = { 0xA8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
19+
//uint8_t atapi_packet[12] = { 0xA8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
20+
21+
void _declspec(naked) IDE_primary_channel_interrupt_handler()
22+
{
23+
__asm
24+
{
25+
push ebp
26+
mov ebp, esp
27+
}
28+
29+
++interrupts_fired;
30+
31+
if (debugLevel)
32+
terminal_writestring(" --------- IDE 0 interrupt fired! -------\n");
33+
34+
ide_irq_invoked = true;
35+
36+
PIC_sendEOI(HARDWARE_INTERRUPTS_BASE + channels[0].irq);
37+
38+
if (debugLevel)
39+
terminal_writestring(" --------- IDE 0 interrupt done! -------\n");
40+
41+
_asm
42+
{
43+
pop ebp
44+
iretd
45+
}
46+
}
47+
void _declspec(naked) IDE_secondary_channel_interrupt_handler()
48+
{
49+
__asm
50+
{
51+
push ebp
52+
mov ebp, esp
53+
}
54+
55+
++interrupts_fired;
56+
57+
if (debugLevel)
58+
terminal_writestring(" --------- IDE 1 interrupt fired! -------\n");
59+
60+
ide_irq_invoked = true;
61+
62+
PIC_sendEOI(HARDWARE_INTERRUPTS_BASE + channels[1].irq);
63+
64+
if (debugLevel)
65+
terminal_writestring(" --------- IDE 1 interrupt done! -------\n");
66+
67+
_asm
68+
{
69+
pop ebp
70+
iretd
71+
}
72+
}
1573

1674
void IDE_Init(uint8_t bus, uint8_t slot, uint8_t function)
1775
{
@@ -50,27 +108,139 @@ void IDE_Init(uint8_t bus, uint8_t slot, uint8_t function)
50108
channels[1].irq = 15;
51109
kprintf(" - IRQs %d&%d\n", channels[0].irq, channels[1].irq);
52110

111+
// Register the IRQ handlers
112+
Set_IDT_Entry((unsigned long)IDE_primary_channel_interrupt_handler,
113+
HARDWARE_INTERRUPTS_BASE + channels[0].irq);
114+
Set_IDT_Entry((unsigned long)IDE_secondary_channel_interrupt_handler,
115+
HARDWARE_INTERRUPTS_BASE + channels[1].irq);
116+
117+
// Tell the PIC to enable the IRQ
118+
IRQ_Enable_Line(channels[0].irq);
119+
IRQ_Enable_Line(channels[1].irq);
120+
53121
IDE_Present = true;
54122

123+
channels[0].bmide = PCI_GetBaseAddress4(bus, slot, function) & ~3; // Bus Master IDE
124+
channels[1].bmide = (PCI_GetBaseAddress4(bus, slot, function) & ~3) + 8; // Bus Master IDE
125+
126+
// 2- Disable IRQs: TODO: Need to disable interrupts per-device
127+
IDE_WriteRegister(ATA_PRIMARY_CHANNEL, ATA_REG_CONTROL, ATA_CONTROL_REG_DISABLE_INTERRUPTS);
128+
IDE_WriteRegister(ATA_SECONDARY_CHANNEL, ATA_REG_CONTROL, ATA_CONTROL_REG_DISABLE_INTERRUPTS);
129+
130+
// 3- Detect ATA-ATAPI Devices:
131+
int driveNumber = 0;
132+
for (uint8_t channel = 0; channel < 2; channel++)
133+
{
134+
for (uint8_t device = 0; device < 2; device++)
135+
{
136+
uint8_t err = 0, type = IDE_ATA, status;
137+
ide_devices[driveNumber].Present = 0; // Assuming that no drive here.
138+
139+
// (I) Select Drive:
140+
IDE_WriteRegister(channel, ATA_REG_HDDEVSEL, 0xA0 | (device << 4)); // Select Drive.
141+
TimeDelayMS(1); // Wait 1ms for drive select to work.
142+
//return;
143+
// (II) Send ATA Identify Command:
144+
IDE_WriteRegister(channel, ATA_REG_COMMAND, ATA_CMD_IDENTIFY);
145+
TimeDelayMS(1);
146+
147+
// (III) Polling:
148+
if (IDE_ReadRegister(channel, ATA_REG_STATUS) == 0)
149+
continue; // If Status = 0, No Device.
150+
151+
// TODO: Timeout
152+
while (1)
153+
{
154+
status = IDE_ReadRegister(channel, ATA_REG_STATUS);
155+
if ((status & ATA_SR_ERR))
156+
{
157+
err = 1; break;
158+
} // If Err, Device is not ATA.
159+
if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRQ))
160+
break; // Everything is right.
161+
}
162+
163+
// (IV) Probe for ATAPI Devices:
164+
if (err != 0)
165+
{
166+
unsigned char cl = IDE_ReadRegister(channel, ATA_REG_LBA1);
167+
unsigned char ch = IDE_ReadRegister(channel, ATA_REG_LBA2);
168+
169+
if (cl == 0x14 && ch == 0xEB)
170+
type = IDE_ATAPI;
171+
else if (cl == 0x69 && ch == 0x96)
172+
type = IDE_ATAPI;
173+
else
174+
continue; // Unknown Type (may not be a device).
175+
176+
IDE_WriteRegister(channel, ATA_REG_COMMAND, ATA_CMD_IDENTIFY_PACKET);
177+
TimeDelayMS(1);
178+
}
179+
180+
// (V) Read Identification Space of the Device:
181+
IDE_ReadBuffer(channel, ATA_REG_DATA, (uint32_t *)ide_buf, 128);
182+
183+
// (VI) Read Device Parameters:
184+
ide_devices[driveNumber].Present = 1;
185+
ide_devices[driveNumber].Type = type;
186+
ide_devices[driveNumber].Channel = channel;
187+
ide_devices[driveNumber].Drive = device;
188+
ide_devices[driveNumber].Signature = *((unsigned short *)(ide_buf + ATA_IDENT_DEVICETYPE));
189+
ide_devices[driveNumber].Capabilities = *((unsigned short *)(ide_buf + ATA_IDENT_CAPABILITIES));
190+
ide_devices[driveNumber].CommandSets = *((unsigned int *)(ide_buf + ATA_IDENT_COMMANDSETS));
191+
192+
// (VII) Get Size:
193+
if (ide_devices[driveNumber].CommandSets & (1 << 26))
194+
// Device uses 48-Bit Addressing:
195+
ide_devices[driveNumber].Size = *((unsigned int *)(ide_buf + ATA_IDENT_MAX_LBA_EXT));
196+
else
197+
// Device uses CHS or 28-bit Addressing:
198+
ide_devices[driveNumber].Size = *((unsigned int *)(ide_buf + ATA_IDENT_MAX_LBA));
199+
200+
// (VIII) String indicates model of device (like Western Digital HDD and SONY DVD-RW...):
201+
// model string is stored with every two bytes swapped
202+
for (int k = 0; k < IDE_MODEL_STRING_LENGTH; k += 2)
203+
{
204+
ide_devices[driveNumber].Model[k] = ide_buf[ATA_IDENT_MODEL + k + 1];
205+
ide_devices[driveNumber].Model[k + 1] = ide_buf[ATA_IDENT_MODEL + k];
206+
}
207+
ide_devices[driveNumber].Model[IDE_MODEL_STRING_LENGTH] = 0; // Terminate String.
208+
209+
driveNumber++;
210+
}
211+
}
212+
213+
// 4- Print Summary:
214+
for (int i = 0; i < 4; i++)
215+
{
216+
if (ide_devices[i].Present == 1)
217+
{
218+
kprintf(" Found %s Drive - %s\n",
219+
ide_devices[i].Type ? "ATAPI" : "ATA", // type
220+
//ide_devices[i].Size / 1024 / 1024 / 2, // size
221+
ide_devices[i].Model);
222+
}
223+
}
224+
55225
kprintf(" IDE controller driver initialized\n");
56226
}
57227

58-
uint8_t ide_polling(uint8_t channel, uint8_t advanced_check)
228+
uint8_t IDE_PollUntilNotBSY(uint8_t channel, uint8_t advanced_check)
59229
{
60230

61231
// (I) Delay 400 nanosecond for BSY to be set:
62232
// -------------------------------------------------
63233
for (int i = 0; i < 4; i++)
64-
ide_read(channel, ATA_REG_ALTSTATUS); // Reading the Alternate Status port wastes 100ns; loop four times.
234+
IDE_ReadRegister(channel, ATA_REG_ALTSTATUS); // Reading the Alternate Status port wastes 100ns; loop four times.
65235

66236
// (II) Wait for BSY to be cleared:
67237
// TODO: add timeout
68-
while (ide_read(channel, ATA_REG_STATUS) & ATA_SR_BSY)
238+
while (IDE_ReadRegister(channel, ATA_REG_STATUS) & ATA_SR_BSY)
69239
; // Wait for BSY to be zero.
70240

71241
if (advanced_check)
72242
{
73-
uint8_t state = ide_read(channel, ATA_REG_STATUS); // Read Status Register.
243+
uint8_t state = IDE_ReadRegister(channel, ATA_REG_STATUS); // Read Status Register.
74244

75245
// (III) Check For Errors:
76246
if (state & ATA_SR_ERR)
@@ -89,13 +259,13 @@ uint8_t ide_polling(uint8_t channel, uint8_t advanced_check)
89259
return 0; // No Error.
90260
}
91261

92-
uint8_t ide_read(uint8_t channel, uint8_t reg)
262+
uint8_t IDE_ReadRegister(uint8_t channel, uint8_t reg)
93263
{
94-
uint8_t result;
264+
uint8_t result = 0;
95265

96-
// If we're writing to register ATA_REG_SECCOUNT1 or ATA_REG_LBAx (the second device on the channel)
266+
// If we're reading from register ATA_REG_SECCOUNT1 or ATA_REG_LBA3 - 5 (the second device on the channel)
97267
if (reg >= ATA_REG_SECCOUNT1 && reg <= ATA_REG_LBA5)
98-
ide_write(channel, ATA_REG_CONTROL, 0x80 | channels[channel].disableInterrupts);
268+
IDE_WriteRegister(channel, ATA_REG_CONTROL, 0x80 | channels[channel].disableInterrupts);
99269

100270
if (reg <= ATA_REG_COMMAND)
101271
result = inb(channels[channel].base + reg - 0x00);
@@ -106,18 +276,47 @@ uint8_t ide_read(uint8_t channel, uint8_t reg)
106276
else if (reg < 0x16)
107277
result = inb(channels[channel].bmide + reg - 0x0E);
108278

109-
// If we're writing to register ATA_REG_SECCOUNT1 or ATA_REG_LBAx (the second device on the channel)
279+
// If we're reading from register ATA_REG_SECCOUNT1 or ATA_REG_LBA3 - 5 (the second device on the channel)
110280
if (reg >= ATA_REG_SECCOUNT1 && reg <= ATA_REG_LBA5)
111-
ide_write(channel, ATA_REG_CONTROL, channels[channel].disableInterrupts);
281+
IDE_WriteRegister(channel, ATA_REG_CONTROL, channels[channel].disableInterrupts);
112282

113283
return result;
114284
}
115285

116-
void ide_write(uint8_t channel, uint8_t reg, uint8_t data)
286+
// TODO: Adapted from OSDev.org, need to rewrite in my own style
287+
void IDE_ReadBuffer(uint8_t channel, uint8_t reg, uint32_t *buffer, unsigned int quads)
288+
{
289+
if (reg > 0x07 && reg < 0x0C)
290+
IDE_WriteRegister(channel, ATA_REG_CONTROL, 0x80 | channels[channel].disableInterrupts);
291+
292+
for (unsigned int i = 0; i < quads; ++i)
293+
{
294+
if (reg < 0x08)
295+
buffer[i] = inl(channels[channel].base + reg - 0x00);
296+
else if (reg < 0x0C)
297+
buffer[i] = inl(channels[channel].base + reg - 0x06);
298+
else if (reg < 0x0E)
299+
buffer[i] = inl(channels[channel].ctrl + reg - 0x0A);
300+
else if (reg < 0x16)
301+
buffer[i] = inl(channels[channel].bmide + reg - 0x0E);
302+
}
303+
304+
if (reg > 0x07 && reg < 0x0C)
305+
IDE_WriteRegister(channel, ATA_REG_CONTROL, channels[channel].disableInterrupts);
306+
}
307+
308+
void IDE_WaitForIRQ()
309+
{
310+
while (!ide_irq_invoked)
311+
;
312+
ide_irq_invoked = false;
313+
}
314+
315+
void IDE_WriteRegister(uint8_t channel, uint8_t reg, uint8_t data)
117316
{
118-
// If we're writing to register ATA_REG_SECCOUNT1 or ATA_REG_LBAx (the second device on the channel)
317+
// If we're writing to register ATA_REG_SECCOUNT1 or ATA_REG_LBA3 - 5 (the second device on the channel)
119318
if (reg >= ATA_REG_SECCOUNT1 && reg <= ATA_REG_LBA5)
120-
ide_write(channel, ATA_REG_CONTROL, 0x80 | channels[channel].disableInterrupts);
319+
IDE_WriteRegister(channel, ATA_REG_CONTROL, 0x80 | channels[channel].disableInterrupts);
121320

122321
if (reg <= ATA_REG_COMMAND)
123322
outb(channels[channel].base + reg - 0x00, data);
@@ -128,7 +327,7 @@ void ide_write(uint8_t channel, uint8_t reg, uint8_t data)
128327
else if (reg < 0x16)
129328
outb(channels[channel].bmide + reg - 0x0E, data);
130329

131-
// If we're writing to register ATA_REG_SECCOUNT1 or ATA_REG_LBAx (the second device on the channel)
330+
// If we're writing to register ATA_REG_SECCOUNT1 or ATA_REG_LBA3 - 5 (the second device on the channel)
132331
if (reg >= ATA_REG_SECCOUNT1 && reg <= ATA_REG_LBA5)
133-
ide_write(channel, ATA_REG_CONTROL, channels[channel].disableInterrupts);
332+
IDE_WriteRegister(channel, ATA_REG_CONTROL, channels[channel].disableInterrupts);
134333
}

0 commit comments

Comments
 (0)