Skip to content
This repository has been archived by the owner on Nov 21, 2017. It is now read-only.

Call os_command_line on Newlib _exit function call #83

Closed
wants to merge 1 commit into from
Closed

Call os_command_line on Newlib _exit function call #83

wants to merge 1 commit into from

Conversation

vilhelmgray
Copy link
Contributor

This should fix the infinite loop problem in issue #50 by calling the OS command line subroutine on a Newlib _exit function call.

However, I have noticed a regression with this fix: upon executing the command line exit command after a program calls the Newlib _exit function, a General Protection fault occurs. We should investigate the cause of this regression before closing issue #50.

@benaryorg
Copy link
Contributor

I think calling the command line is a very bad idea.

First of all, call is meant for code that does actually return.
This does not return so we should probably use jmp.

I will look into that.…

@benaryorg
Copy link
Contributor

programs are functions

/os/cli.asm on line 78 calls the program too.

So we need to return to that piece of code.

solutions

simple returning

All we need to do that:

  1. we need the stackpointer to be exactly what it was when the program started execution
  2. then we need to place a ret statement there

This is (or should be) what happens after the program finished execution.

The problem is that the program need not have finished executing, so we needed some sort of bootstrapping.

rebooting

The easiest solution (and probably the most safe one) would be to reboot the whole operating system. Note that I am talking about the OS, not the computer. The OS would need to disable all processors, it's stack and a few other things and jmp back to kernel_start.

resetting one processor

As mentioned above, we have multiple processors.

If we look at /os/kernel64.asm on line 72, we see this comment:

All cores start here on first start-up and after an exception

What does that mean?

We are working in a multithreaded environment, that means, if we call exit we either want to stop the whole program (which, in a single-process OS would lead to, more or less, rebooting the OS so, see above) or we want to exit our current thread.

Exiting our thread works by simply resetting it's stack and waiting for a new workload.
Unfortunately this is exactly what happens in ap_clear (see the above links).

So in this scenario, the whole thread would just stop and opt out of existence.
Just blame the programmers if they forget to unlock mutexes.

what do we really want

As far as I know, newlib is trying to provide the same functionality (or at least a subset) as the standard C library. Please correct me if I am wrong.

If, in C, the exit(0) is called, it exit's the whole program.

To reproduce this the newlib would need to reset the whole OS (or at least some parts of it) as pointed out above. This would also fix #50.

Also it would be useful to have a syscall/function or something to exit the current thread (if that isn't yet implemented).

@benaryorg benaryorg mentioned this pull request Jun 27, 2015
@IanSeyler
Copy link
Member

Agreed @benaryorg !

Calling the CLI again is not the proper method... especially if a multi-threaded process exits while other CPU cores are still executing code.

Looking into a fix for this that will involve resetting all CPU cores and restarting the CLI.

@ohnx
Copy link
Contributor

ohnx commented Jul 7, 2015

would the ret assembly call do anything in this case?

@benaryorg
Copy link
Contributor

It exit() really resets all processors then the ret will never get executed. It will only have an effect if your custom programs main function returns.

@ohnx
Copy link
Contributor

ohnx commented Jul 8, 2015

Well, could another possible solution be to call the kernel again?
ie, jump to the start of the os and let everything re-initialize

@Roxxik
Copy link
Contributor

Roxxik commented Jul 8, 2015

Isn't the easiest thing to just jmp to reboot?

2015-07-08 16:09 GMT+02:00 Mason X notifications@github.com:

Well, could another possible solution be to call the kernel again?
ie, jump to the start of the os and let everything re-initialize


Reply to this email directly or view it on GitHub
https://github.com/ReturnInfinity/BareMetal-OS/pull/83#issuecomment-119592112
.

@ohnx
Copy link
Contributor

ohnx commented Jul 8, 2015

but that's rebooting, which is different from resetting.

@benaryorg
Copy link
Contributor

Also, please keep in mind that we have multiple processors (or at least
threads) which are not just going to stop it one of them does.

One solution would be, to let them a l get an exception.

Then there would only be left the reset of the memory structures (e.g.
memory allocations).

How about using paging to reset all threads?
First emptying the smp-queue and then unmapping all memory allocated for
the program and the user allocated memory would do the trick I think.

@IanSeyler
Copy link
Member

@benaryorg is correct.

The current plan is to add a system call (in b_system_misc) that does the following:
-clear memory map
-clear network and RTC callbacks
-reset all CPU cores to jump to ap_clear in kernel64.asm (there is already an interrupt vector for this)
-restart the CLI

@benaryorg
Copy link
Contributor

Is it possible, and if yes, how, to send an interrupt to all processors?

@ohnx
Copy link
Contributor

ohnx commented Jul 8, 2015

loop through all processors?

@benaryorg
Copy link
Contributor

Sorry, I wasn't clear enough.

What I meant was:

How would that look in Assembly code?

I quickly looked around the internet and found this Wikipedia Article but it is a bit short.
It would be great if someone of you added some sample code for x86_64 there.

@IanSeyler
Copy link
Member

Here is how BareMetal inits the CPUs: https://github.com/ReturnInfinity/BareMetal-kernel/blob/master/src/x86-64/init/64.asm#L163

I just need to adjust the code for the new reset function. I don't want to reset the calling CPU core accidentally so will need to call os_smp_get_id first.

os_smp_reset: https://github.com/ReturnInfinity/BareMetal-OS/blob/master/os/syscalls/smp.asm#L19

That code send a message via the APIC to a specific CPU core telling it to execute interrupt 0x81 which is ap_clear in kernel64.asm

@IanSeyler
Copy link
Member

@benaryorg For IPI code you can take a look here: https://github.com/ReturnInfinity/Pure64/blob/master/src/init/smp.asm

That is the code for how Pure64 (The BareMetal bootloader) 'boots' up the other CPU cores.

@benaryorg
Copy link
Contributor

@IanSeyler Thanks a lot!

@benaryorg
Copy link
Contributor

You could, just to be sure to have everything cleaned up, do something like this then:

  • clear smp_queue
  • reset all CPU cores, but the calling one
  • clear memory map
  • clear network and RTC callbacks
  • enqueue the CLI
  • reset the calling CPU

@IanSeyler
Copy link
Member

@benaryorg 👍

@IanSeyler
Copy link
Member

This should be properly addressed in the last push: ReturnInfinity/BareMetal-OS@59d15a4

@IanSeyler IanSeyler closed this Jul 8, 2015
@vilhelmgray vilhelmgray deleted the fix_exit_call_crash branch July 9, 2015 22:29
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants