Skip to content

Commit 30aeb9f

Browse files
author
tthomps
committed
Add ExitApp() function for exiting multitasking apps with the exit() system call. Soon ExitApp() will also be the way that apps returning from main() will exit.
Add some code to timer_interrupt_handler() to check if a task has quit, and delete a ready queue entry if so. Add stack trace to invalid opcode handler. Expand simple debugger to check the module name to see which map file to load (only the kernel map file is implementing at the moment) and not lookup mappings in unknown modules. However, check the address and if the mapping is in kernel space, then look up the address from the kernel map. Also, reload map files when the kernel has been relaunched. Add a temporary fix to TFTP to keep track of which task requested the file. If the TFTP receive packet handler is called when another task is running, switch to the page table of the task that requested the file, then switch back when we're done. This is only a hack and doesn't work in all cases. The next step is probably to implement kmalloc() so networking functions and drivers can allocate memory in kernel space without fear of causing a page fault later - this should be a permanent fix when it's implemented. Remove GUI.map from repo (.map files change too much with each commit and it throws off my line count).
1 parent 586bd9e commit 30aeb9f

File tree

16 files changed

+230
-3601
lines changed

16 files changed

+230
-3601
lines changed

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 6401
6+
BUILD_NUMBER 6438

MyOS_1/Debugging/Debug.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ void DebugStackTrace(unsigned int MaxFrames)
1515
{
1616
// Unwind to previous stack frame
1717
serial_printf("0x%X\n", pStackFrame->eip);
18+
if (pStackFrame->eip == 0)
19+
break;
1820
pStackFrame = pStackFrame->ebp;
1921
}
2022
}

MyOS_1/Interrupts/Interrupts.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,8 @@ void _declspec(naked) exit_interrupt_handler(int eflags, int cs)
183183
// supress warning about unused parameters
184184
(void)eflags, (void)cs;
185185

186-
longjmp(peReturnBuf, 42);
186+
//longjmp(peReturnBuf, 42); // Not only do I not like this way of exitting, it doesn't work right now
187+
ExitApp();
187188

188189
// No need for iretd because we'll never return here
189190
}
@@ -637,10 +638,13 @@ void _declspec(naked) invalid_opcode_handler(void)
637638
{
638639
pop [address]
639640
}
640-
641+
641642
terminal_fill(' ', VGA_COLOR_WHITE, VGA_COLOR_BLUE);
642643
terminal_writestring("Invalid opcode handler fired.\nEncountered invalid opcode at ");
643644
terminal_print_ulong_hex(address);
645+
646+
DebugStackTrace(10);
647+
644648
terminal_writestring(".\nMemory looks like:\n");
645649
terminal_dumpHexAround((uint8_t *)address, 128, 128);
646650
terminal_writestring("System halted.\n");
@@ -787,7 +791,6 @@ void _declspec(naked) printf_interrupt_handler(int eflags, int cs, const char *f
787791
GUI_printf(fmt, va);
788792
else
789793
vprintf_(fmt, va);
790-
791794

792795
_asm
793796
{

MyOS_1/Interrupts/System_Calls.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@
99
#include "../Drivers/Keyboard.h"
1010

1111

12-
void SystemCallExit()
12+
void SystemCallExit(int returnCode)
1313
{
14+
// returnCode is ignored for now
15+
(void)returnCode;
16+
1417
//printf("exit called\n");
1518

1619
__asm

MyOS_1/Interrupts/System_Calls.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ extern "C" {
3232
#define SYSCALL_REGISTER_GUI_CALLBACK 238
3333
#define SYSCALL_LAUNCH_APP 237
3434

35-
void SystemCallExit();
35+
void SystemCallExit(int returnCode);
3636
#define exit SystemCallExit
3737

3838
int SystemCallFClose(FILE *fp);

MyOS_1/Networking/TFTP.c

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "../Terminal.h"
44
#include "Ethernet.h"
55
#include "../Drivers/Virtio_Net.h"
6+
#include "../Tasks/Context.h"
67

78
// TODO: Support multiple transactions
89
uint16_t transactionID;
@@ -16,6 +17,7 @@ uint8_t *nextFilePointer;
1617
uint16_t currentBlockNumber;
1718
uint16_t virtualBoxBlockNumber; // workaround for VirtualBox's bullshit
1819
uint32_t tftpFileSize;
20+
uint32_t tftpTaskIndex; // TEMPTEMP HACKHACK
1921

2022
uint32_t tftpServerIP; // TODO, maybe, support more than one server
2123

@@ -30,9 +32,16 @@ bool TFTP_TransactionComplete()
3032
// will block until the file is transacted
3133
// TODO: Implement timeout, error-checking
3234
// TODO: Fix hanging if an invalid serverIP is given
35+
// TODO: We'll need mutexes or some other sync method to support multiple tasks
36+
// And / Or we'll need to replace globals with per-task variables
3337
// actualFileSize can be NULL if the caller doesn't care about the size
3438
bool TFTP_GetFile(uint32_t serverIP, const char *filename, uint8_t *destinationBuffer, uint32_t maxFileSize, uint32_t *actualFileSize)
3539
{
40+
// TEMPTEMP HACKHACK block until any existing transfers have completed
41+
while (transferInProgress)
42+
{
43+
}
44+
3645
if(actualFileSize)
3746
*actualFileSize = 0;
3847

@@ -41,6 +50,7 @@ bool TFTP_GetFile(uint32_t serverIP, const char *filename, uint8_t *destinationB
4150

4251
tftpFileBuffer = destinationBuffer;
4352
tftpFileBufferSize = maxFileSize;
53+
tftpTaskIndex = currentTask;
4454

4555
if (debugLevel)
4656
{
@@ -79,6 +89,11 @@ bool TFTP_GetFile(uint32_t serverIP, const char *filename, uint8_t *destinationB
7989
// Retrieves the size of a file. This can take a while for large files, because we actually have to retrieve the entire file to know its size.
8090
bool TFTP_GetFileSize(uint32_t serverIP, const char *filename, uint32_t *pActualFileSize)
8191
{
92+
// TEMPTEMP HACKHACK block until any existing transfers have completed
93+
while (transferInProgress)
94+
{
95+
}
96+
8297
// Ensure pActualFileSize is a valid pointer
8398
if (!pActualFileSize)
8499
return false;
@@ -88,6 +103,7 @@ bool TFTP_GetFileSize(uint32_t serverIP, const char *filename, uint32_t *pActual
88103

89104
// TFTP doesn't support retreiving a file's size, so we request the file from the server, but don't store the file returned
90105
determiningFileSize = true;
106+
tftpTaskIndex = currentTask;
91107

92108
// Request the file from the server
93109
TFTP_RequestFile(serverIP, filename, TFTP_TYPE_BINARY, NIC_MAC);
@@ -247,9 +263,44 @@ void TFTP_ProcessDataPacket(TFTP_DataHeader *dataPacket, uint16_t sourcePort, ui
247263

248264
if (!determiningFileSize)
249265
{
250-
// copy received data to the file buffer
251-
memcpy(nextFilePointer, dataPacket->data, dataSize);
252-
nextFilePointer += dataSize;
266+
// TEMPTEMP HACKHACK
267+
// Now we've received some data, but we have to be careful because the task that's currently active
268+
// may not have the same virtual memory space as the task that gave us the destination buffer.
269+
// We need to ensure interrupts are disabled because we can't allow a context switch while we play with page tables.
270+
__asm
271+
{
272+
// TODO: Are interrupts already disabled when we reach this code? Need to check on that.
273+
pushf
274+
cli
275+
}
276+
277+
// Ensure we have the proper page directory loaded for nextFilePointer for the task which requested the file
278+
if (currentTask == tftpTaskIndex || tasks[currentTask].cr3 == tasks[tftpTaskIndex].cr3)
279+
{
280+
// We don't need to do anything with paging
281+
282+
// copy received data to the file buffer
283+
memcpy(nextFilePointer, dataPacket->data, dataSize);
284+
nextFilePointer += dataSize;
285+
}
286+
else
287+
{
288+
// We need to swap out the page directory with the one for the task that requested the file
289+
__writecr3(tasks[tftpTaskIndex].cr3);
290+
291+
// copy received data to the file buffer
292+
memcpy(nextFilePointer, dataPacket->data, dataSize);
293+
nextFilePointer += dataSize;
294+
295+
// restore the page directory of the current task
296+
__writecr3(tasks[currentTask].cr3);
297+
}
298+
299+
// Restore interrupt state
300+
__asm
301+
{
302+
popf
303+
}
253304
}
254305

255306
tftpFileSize += dataSize;

MyOS_1/Tasks/Context.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ extern bool multiEnable; // TEMPTEMP
6161

6262
void DispatchNewTask(uint32_t programStart, PAGE_DIRECTORY_ENTRY *newPageDirectory, uint32_t stackSize, const char *imageName, bool exclusive);
6363

64+
void ExitApp();
65+
6466
bool LaunchApp(const char *appName, int exclusive, uint32_t exeLocation);
6567

6668
void SwitchTask(uint32_t taskIndex);

MyOS_1/Tasks/Dispatcher.c

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ void DispatchNewTask(uint32_t programStart, PAGE_DIRECTORY_ENTRY *newPageDirecto
6969

7070
// Create ready queue entry
7171
READY_QUEUE_ENTRY *queueEntry;
72-
queueEntry = malloc(sizeof(READY_QUEUE_ENTRY));
72+
queueEntry = dbg_alloc(sizeof(READY_QUEUE_ENTRY));
7373
// TODO: Exitting programs will need to be cleaned up somehow
7474
if (!queueEntry)
7575
{
@@ -193,4 +193,43 @@ bool LaunchApp(const char *appName, int exclusive, uint32_t exeLocation)
193193
dbg_release(peBuffer);
194194

195195
return succeeded;
196+
}
197+
198+
// This is where a running program will "return" to. We can also call it with the exit system call
199+
void ExitApp()
200+
{
201+
// Make sure interrupts are disabled
202+
_disable();
203+
204+
// TODO: handle multiEnable = false
205+
// If the ready-queue is empty or contains only this task,
206+
// or if we're not running in multitasking mode, there's nothing we can do here
207+
if (!readyQueueHead || (!readyQueueHead->nextEntry && readyQueueHead->taskIndex == currentTask))
208+
{
209+
kprintf("ExitApp called on only running app. System halted");
210+
for (;;)
211+
__halt();
212+
}
213+
214+
// Allow the task index to be reused
215+
tasks[currentTask].inUse = false;
216+
217+
// TODO: Free all memory associated with this task
218+
// TODO: Free the stack or mark it as reusable (not sure how to do this right now)
219+
220+
// Make sure this task can be swapped out ASAP
221+
tasks[currentTask].exclusive = false;
222+
ticksLeftInTask = 0;
223+
224+
printf("\n%s has exited.\n", tasks[currentTask].imageName);
225+
226+
// TODO: Tell the GUI the program has quit
227+
228+
// Enable interrupts
229+
_enable();
230+
231+
// TODO: Is there a better way to switch contexts from here?
232+
// Now we'll just wait for the timer interrupt to fire and this task will never be revisitted
233+
for (;;)
234+
__halt();
196235
}

MyOS_1/Timers/PIT.c

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -102,31 +102,53 @@ void _declspec(naked) timer_interrupt_handler(void)
102102
// Pull info from the front of the ready queue
103103
currentTask = readyQueueHead->taskIndex;
104104

105-
// Move the current task to the end of the ready queue
106-
// Are there more than two ready queue entries?
107-
if (readyQueueHead != finalReadyQueueEntry)
105+
// Is the old task still running?
106+
if (tasks[oldTaskIndex].inUse)
108107
{
109-
readyQueueHead->taskIndex = oldTaskIndex;
110-
finalReadyQueueEntry->nextEntry = readyQueueHead;
111-
oldHead = readyQueueHead;
112-
readyQueueHead = readyQueueHead->nextEntry;
113-
oldHead->nextEntry = NULL;
108+
// Move the current task to the end of the ready queue
109+
// Are there more than two ready queue entries?
110+
if (readyQueueHead != finalReadyQueueEntry)
111+
{
112+
readyQueueHead->taskIndex = oldTaskIndex;
113+
finalReadyQueueEntry->nextEntry = readyQueueHead;
114+
oldHead = readyQueueHead;
115+
readyQueueHead = readyQueueHead->nextEntry;
116+
oldHead->nextEntry = NULL;
117+
}
118+
else
119+
{
120+
readyQueueHead->taskIndex = oldTaskIndex;
121+
}
114122
}
115123
else
116124
{
117-
readyQueueHead->taskIndex = oldTaskIndex;
125+
// The old task has quit, so we shouldn't add it to the ready queue and we have to
126+
// free a ready queue entry or else we'll have one too many
127+
128+
// Is there more than one ready queue entry?
129+
if (readyQueueHead->nextEntry)
130+
{
131+
oldHead = readyQueueHead;
132+
readyQueueHead = readyQueueHead->nextEntry;
133+
dbg_release(oldHead);
134+
}
135+
else
136+
{
137+
dbg_release(readyQueueHead);
138+
readyQueueHead = NULL;
139+
}
118140
}
119141

120142
if(debugLevel)
121143
kprintf(" Switching to %s\n", tasks[currentTask].imageName);
122144

123145
ticksLeftInTask = TICKS_PER_TASK;
124146

125-
// switch to the new task's page tables
147+
// Switch to the new task's page tables
126148
if(tasks[currentTask].cr3 != __readcr3())
127149
__writecr3(tasks[currentTask].cr3);
128150

129-
// Get the stack pointer of the next waiting task and make that the stack
151+
// Set the stack pointer to the stack pointer of the new task
130152
espVal = tasks[currentTask].ESP;
131153

132154
if(debugLevel)

MyOS_1/myos_io.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
OPEN_FILES openFiles = { 0 };
77

8+
extern uint32_t currentTask;
9+
810
int file_close(int fp)
911
{
1012
if (fp >= MAX_FILES || fp < 0)
@@ -58,18 +60,22 @@ int file_open(const char * filename, const char * mode)
5860
return -1;
5961
}
6062

63+
openFiles.buffer[index] = buffer;
64+
openFiles.taskIndex[index] = currentTask;
65+
openFiles.isOpen[index] = true;
66+
6167
if (!TFTP_GetFile(tftpServerIP, (char *)filename, buffer, fileSize, NULL))
6268
{
6369
kprintf("Not able to open %s", filename);
70+
openFiles.isOpen[index] = false;
6471
return -1;
6572
}
6673

6774
strncpy(openFiles.filename[index], filename, MAX_PATH);
6875
openFiles.filePos[index] = 0;
6976
openFiles.fileSize[index] = fileSize;
7077
openFiles.readOnly[index] = true;
71-
openFiles.isOpen[index] = true;
72-
openFiles.buffer[index] = buffer;
78+
7379

7480
kprintf("opened %s in slot %d\n", filename, index);
7581

0 commit comments

Comments
 (0)