Skip to content
This repository has been archived by the owner on Dec 9, 2018. It is now read-only.

Long mode #8

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open

Long mode #8

wants to merge 5 commits into from

Conversation

japaric
Copy link
Contributor

@japaric japaric commented Sep 18, 2016

@japaric
Copy link
Contributor Author

japaric commented Sep 18, 2016

@homunkulus try

@homunkulus
Copy link
Collaborator

⌛ Trying commit bcc0c6a with merge bcc0c6a...

@homunkulus
Copy link
Collaborator

💔 Test failed - status-travis

accessed via pure Rust, AFAIK. For that reason, this part is written in inline assembly.
- Caveat: Because we are telling `rustc` to use a 32-bit target, `rustc` always emit 32-bit
instructions and we can't actually use 64-bit instructions/registers in the section of the program
where the CPU is already in long mode. Yikes, I'll have to think about how to solve this.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can be solved by splitting this crate in two: one crates that does the booting process and is compiled for a 32-bit target and the other crate that exposes the long_mode_start symbol and is compiled for a 64-bit target. The issue is that I think the compiler won't link together crates compiled for different types (imagine mixing a crate compiled for ARM with a crate compiled for x86). If that's the case we could compiled the boot crate as a staticlib and link that staticlib into the long crate. That should bypass the "same target" check.

All this is speculation from my part. I don't know if it will actually work.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds about right to me.

the target changed
@japaric
Copy link
Contributor Author

japaric commented Sep 18, 2016

@homunkulus try

@homunkulus
Copy link
Collaborator

⌛ Trying commit 2ed58d5 with merge 2ed58d5...

// extra selector
asm!("mov es, ax" :::: "intel");

// FIXME Is this the right syntax for a far jump?
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thought on this part?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think so? Not 100% sure though.

@homunkulus
Copy link
Collaborator

💔 Test failed - status-travis

it fails to link for some reason :-/
@japaric
Copy link
Contributor Author

japaric commented Sep 18, 2016

@homunkulus try

@homunkulus
Copy link
Collaborator

⌛ Trying commit 137b345 with merge 137b345...

@homunkulus
Copy link
Collaborator

☀️ Test successful - status-travis
State: approved= try=True

accessed via pure Rust, AFAIK. For that reason, this part is written in inline assembly.
- Caveat: Because we are telling `rustc` to use a 32-bit target, `rustc` always emit 32-bit
instructions and we can't actually use 64-bit instructions/registers in the section of the program
where the CPU is already in long mode. Yikes, I'll have to think about how to solve this.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds about right to me.


// move page table address to cr3
asm!("mov eax, p4_table
mov cr3, eax" :::: "intel");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://crates.io/crates/x86 would be neat to use here, but it also only supports 64-bit for now, IIRC.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They added support for 32 bit lately, but I'm not sure if it's already on crates.io…

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0.8 on crates.io has the bulk of this.

// extra selector
asm!("mov es, ax" :::: "intel");

// FIXME Is this the right syntax for a far jump?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think so? Not 100% sure though.

@steveklabnik
Copy link

A thought that I've been rolling around in my head, but haven't tried to implement yet.

What about having a build.rs that builds an asm implementation of the booting into long mode? Treat it like any other dependency. It should basically never change, but even if it does, the rerun-if-changed bit could fix it. Then, the Rust code is all x86-64.

@japaric
Copy link
Contributor Author

japaric commented Sep 23, 2016

@steveklabnik That would have to shell out to an external assembler like nasm, right? I would prefer if we didn't have to depend on an external tool but, yes, that should work in principle.

@steveklabnik
Copy link

Yeah, it would still require shelling out. It's not a perfect solution, but
it still lets you get rid of the makefile.

Even worse idea: one huge "inline asm" Rust block? lololol

On Fri, Sep 23, 2016 at 2:48 PM, Jorge Aparicio [email protected]
wrote:

@steveklabnik https://github.com/steveklabnik That would have to shell
out to an external assembler like nasm, right? I would prefer if we
didn't have to depend on an external tool but, yes, that should work in
principle.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#8 (comment), or mute
the thread
https://github.com/notifications/unsubscribe-auth/AABsih7FQ6mQTGGxofMB73wJn4X8Y5aIks5qtB8BgaJpZM4J_8bw
.

@japaric
Copy link
Contributor Author

japaric commented Sep 23, 2016

Another approach that could work is have a single x86_64 target, split the boot code into its own crate, compile that boot crate for x86_64 but use -C target-feature to force the use of 32-bit instructions in that crate and, finally, link that crate with the kernel crate which is compiled normally (in 64-bit mode).

I tried this but I couldn't figure a combination of target-features that produces only 32-bit instructions. +32bit-mode,-64bit,-64bit-mode looked promising but it resulted in an LLVM assertion.

@japaric
Copy link
Contributor Author

japaric commented Sep 23, 2016

Even worse idea: one huge "inline asm" Rust block? lololol

👍. I have actually thought about this! I think it requires global asm instead of inline though (I haven't actually tried)

@steveklabnik
Copy link

I bet you could configure start? Hm.

On Fri, Sep 23, 2016 at 2:54 PM, Jorge Aparicio [email protected]
wrote:

Even worse idea: one huge "inline asm" Rust block? lololol

👍. I have actually thought about this! I think it requires global asm
instead of inline though (I haven't actually tried)


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#8 (comment), or mute
the thread
https://github.com/notifications/unsubscribe-auth/AABsij54rb9qbfGotAfAIAfmohOdNX0cks5qtCBhgaJpZM4J_8bw
.

@phil-opp
Copy link

A naked extern function with #[no_mangle] should work. However, I'm not sure if inline assembly supports the bits 32 directive, which we use to generate 32 bit opcodes in nasm...

@Ericson2314
Copy link

I'm guessing a similar situation arises when using arm's dynamic endianness to mix ABIs. To me this is proof that the problem is general enough that Cargo should get a proper solution for this.

I do believe baking exact targets into packages is bad, so I guess the solution would be "chameleon targets" that change their definition based on the crate being built? On the other hand two such crates may share the same dependency in which case it is should be configured (flags) + compiled differently, so naive per-crate target shape-shifting won't work.

@steveklabnik
Copy link

I implemented the "build using nasm in a build script" over here: intermezzOS/kernel#63

That nasty build script can be made much nicer with the gcc crate, but then you have to use a syntax gcc understands, which isn't nasm. and i haven't taken the time to port it over yet.

I still find #8 (comment) very interesting

@steveklabnik
Copy link

So, I'm giving that idea a try. I got a libboot.a compiled from the rust in this PR, but when trying to make my other code depend on it, I'm getting

= note: /usr/bin/ld: skipping incompatible ./libboot.a when searching for -lboot

So, something must be slightly off. But I think this might work?

@steveklabnik
Copy link

So, @mkpankov pointed out this:

$ readelf -h libboot.a 

File: libboot.a(boot.0.o)
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32

It's going to know that it's a 32-bit ELF file, and not link it in. Given this,

Another approach that could work is have a single x86_64 target, split the boot code into its own crate, compile that boot crate for x86_64 but use -C target-feature to force the use of 32-bit instructions in that crate and, finally, link that crate with the kernel crate which is compiled normally (in 64-bit mode).

Seems like it's probably the correct approach.

@steveklabnik
Copy link

Regarding the "can inline asm do BITS 32", I got a tweet that says yes: https://twitter.com/rpjohnst/status/780474494066450433

@japaric
Copy link
Contributor Author

japaric commented Sep 26, 2016

@steveklabnik did the libboot.a approach work in the end? I tried the two targets, x86 and x86_64, approach and hitted the same problem: the libboot.a (a rust crate compiled as a staticlib) compiled for x86 was a 32-bit elf/library and got ignored by the linker when I tried to link it to the x86_64 kernel crate.

Seems like it's probably the correct approach.

Yeah, but LLVM isn't cooperating :-/.

@steveklabnik
Copy link

I couldn't get it to work, due to the 64/32 issue.

@steveklabnik
Copy link

One other idea I had: if we converted into intel syntax rather than nasm-specific, we could just use the gcc crate to build it. rust already uses gcc for the linker, so that would eliminate one more dep...

p4_table[0] = &p3_table[0] as *const _ as usize as u64 | 0b11;
p3_table[0] = &p2_table[0] as *const _ as usize as u64 | 0b11;

for (entry, i) in p2_table.iter_mut().zip(0..) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.enumerate() rather than zip(0 ?

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.

5 participants