ReturnInfinity / BareMetal-OS-legacy

BareMetal is a 64-bit OS for x86-64 based computers. The OS is written entirely in Assembly while applications can be written in Assembly, C/C++, and Rust.
1.74k stars 303 forks source link

Call os_command_line on Newlib _exit function call #83

Closed vilhelmgray closed 9 years ago

vilhelmgray commented 9 years ago

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 commented 9 years ago

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 commented 9 years ago

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 _kernelstart.

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 _apclear (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).

IanSeyler commented 9 years ago

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 commented 9 years ago

would the ret assembly call do anything in this case?

benaryorg commented 9 years ago

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 commented 9 years ago

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 commented 9 years ago

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 commented 9 years ago

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

benaryorg commented 9 years ago

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 commented 9 years ago

@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 commented 9 years ago

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

ohnx commented 9 years ago

loop through all processors?

benaryorg commented 9 years ago

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 commented 9 years ago

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 commented 9 years ago

@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 commented 9 years ago

@IanSeyler Thanks a lot!

benaryorg commented 9 years ago

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

IanSeyler commented 9 years ago

@benaryorg :+1:

IanSeyler commented 9 years ago

This should be properly addressed in the last push: https://github.com/ReturnInfinity/BareMetal-OS/commit/59d15a4dcf39d77229e51fc4e261f0e437c0e9db