Fix spelling errors in first posts (yikes).

This commit is contained in:
Drew Galbraith 2024-01-23 23:14:03 -08:00
parent adeb3cf394
commit 80e734855c
2 changed files with 18 additions and 17 deletions

View File

@ -111,13 +111,14 @@ On top of the things mentioned above, we use the limine protocol to:
Following boot we immediately initialize the global descriptor table (GDT) and
interrupt descriptor table (IDT). The **GDT** is mostly irrelevant for x86-64,
however it was interesting trying to get it to work with the sysret function
which expects two copies of the user-space segment descriptors to allow returing
to 32bit code from a 64 bit OS. Right now the system doesn't support 32 bit code
(and likely never will) so we just duplicate the 64 bit code segment.
which expects two copies of the user-space segment descriptors to allow
returning to 32bit code from a 64 bit OS. Right now the system doesn't support
32 bit code (and likely never will) so we just duplicate the 64 bit code
segment.
The **IDT** is fairly straightforward and barebones for now. I slowly add more
debugging information to faults as I run into them and it is useful. One of the
biggest improvements was setting up a seperate kernel stack for Page Faults and
biggest improvements was setting up a separate kernel stack for Page Faults and
General Protection Faults. That way if I broke memory related to the current
stack frame I get useful debugging information rather than an immediate triple
fault. I also recently added some very sloppy stack unwind code so I can more
@ -153,9 +154,9 @@ earlier than they need to be it is obvious because things break.
For **virtual memory management** I keep the higher half (kernel) mappings
identical in each address space. Most of the kernel mappings are already
availble from the bootloader but some are added for heaps and additional stacks.
available from the bootloader but some are added for heaps and additional stacks.
For user memory we maintain a tree of the mapped in objects to ensure that none
intersect. Right now the tree is innefficient because it doesn't self balance
intersect. Right now the tree is inefficient because it doesn't self balance
and most objects are inserted in ascending order (i.e. it is essentially a
linked list).
@ -213,7 +214,7 @@ The kernel provides APIs to:
* Allocate memory and map it into an address space.
* Communicate with other processes using Endpoints, Ports, and Channels.
* Register IRQ handlers.
* Manage Capabilites.
* Manage Capabilities.
* Print debug information to the VM output.
### IPC

View File

@ -110,7 +110,7 @@ The short story is that we are looking for the device with the right [class
code](https://wiki.osdev.org/PCI#Class_Codes) - Class Code 0x1 (Storage Device),
Subclass 0x6 (SATA Controller), Subtype 0x1 (AHCI).
Once we have the correct configuration space we cn read the address at offset
Once we have the correct configuration space we can read the address at offset
0x24 (called the ABAR for AHCI Base Address) which points to the start of the
GHC registers.
@ -319,7 +319,7 @@ type and any errors from the interrupt since we aren't sending any commands.
Something I'm not sure about is that as soon as we enable interrupts we seem to
receive a FIS from the device with an error bit set. Both the hard drive and the
optical drive on qemu send a FIS with error bit 0x1 set. Additionally the status
optical drive on QEMU send a FIS with error bit 0x1 set. Additionally the status
field is set to 0x30 for the hard drive and 0x70 for the optical drive.
I was able to find a [OSDev Forum
@ -328,7 +328,7 @@ referencing that this behavior is caused by the reset sending an EXECUTE DEVICE
DIAGNOSTIC command (0x90) to the device. It notes that this is largely
undocumented behavior but at least this information offers some clarity on the
outputs. Reading the ATA Command Set section 7.9.4 we can see that the command
ouputs code 0x01 to the error bits when `Device 0 passed, Device 1 passed or not
outputs code 0x01 to the error bits when `Device 0 passed, Device 1 passed or not
present`. According a footnote we can "See the appropriate transport standard
for the definition of device 0 and device 1." I really thought I was already
looking at the "appropriate transport standard" but alas. All that to say we'll
@ -340,7 +340,7 @@ Now that the AHCI ports are initialized and can handle an interrupt, we can send
commands to them. To start with lets send the IDENTIFY DEVICE command to each
device. This command asks the device to send 512 bytes of information about
itself back to us. These bytes contain 40 years of certified-crufty backwards
compatability. I mean just feast your eyes on the number of retired and obsolete
compatibility. I mean just feast your eyes on the number of retired and obsolete
fields in just the first page of the spec.
![IDENTIFY DEVICE Response](images/IDENTIFY_DEVICE.png)
@ -350,7 +350,7 @@ and sector count from the drive. To do so we need to figure out how to send a
command to the device. To be honest I feel like the specs fall down here in
actually explaining this. The trick is to send a Register Host to Device FIS in one
of the command slots. This FIS type has a field for the command as well as some
common parameters such as lba and count. In retrospect it is fairly clear once
common parameters such as LBA and count. In retrospect it is fairly clear once
you are aware of it, but if you are just reading the SATA spec and looking at
the possible commands, making the logical jump to the Register Host To Device
FIS feels damn near impossible.
@ -379,7 +379,7 @@ Device FIS is as follows:
![Register Host to Device FIS Layout](images/RegisterHostToDeviceFIS.png)
We don't need to initialize most of the fields here because the IDENTIFY_DEVICE
call doesn't rely on an lba or sector count. One of the keys is setting the high
call doesn't rely on an LBA or sector count. One of the keys is setting the high
bit "C" in the byte that contains PM Port which indicates to the HBA that this
FIS contains a new command (I spent a while trying to figure out why this wasn't
working without that). The code for this is relatively straightforward.
@ -429,9 +429,9 @@ port_struct_->command_issue |= (1 << slot);
```
But wait! How will we know when this command has completed? We somehow need to
wait until we receive an interrupt for this command to proccess the data it
wait until we receive an interrupt for this command to process the data it
sent. To handle this we can add a semaphore for each port command slot to allow
signalling when we recieve a completion interrupt for that command. I think it
signalling when we receive a completion interrupt for that command. I think it
might make sense to have some sort of callback instead so we can pass errors
back to the caller instead of just a completion signal. However I'm not sure
what type of errors exist that are resolvable by the caller so for now this
@ -469,7 +469,7 @@ void AhciPort::HandleIrq() {
}
```
Ok now that we have retrieved the information from the drive we can parse it.
OK now that we have retrieved the information from the drive we can parse it.
For the sector size, the default is 512 bytes which we will use unless the
`LOGICAL SECTOR SIZE SUPPORTED` bit is set in double word 106, bit 12. If that
is set we can check the double words at 117 and 118 to get the 32 bit sector
@ -531,7 +531,7 @@ that truly only a mother could love:
![Register Host to Device Layout LBA](images/RegisterHostToDeviceFISLBA.png)
That asside we simply update the FIS construction to set the command, LBA, and
That aside we simply update the FIS construction to set the command, LBA, and
sector count. Following that we set the PRDT values (although we still only use
one slot).