Yes, it gets boxed.
Think about it... for the value not to get boxed there should be some common binary representation that can be any value type - including all built in ones and any struct you may define in the future.
Since such a binary representation doesn't exist the value must be boxed.
Explanation:
When you call a method with parameters the caller places a sequence of bits at an agreed about location and in an agreed about format, for example an int is 32bits with negative numbers encoded as 1-complement, a double is 64bits encoded in IEEE floating point format, etc.
You can't have one method that can except both unboxed int and double because it wouldn't know how many bits to read and how to decode themץ
If you do want a method to accept both you can give the function the memory location of the value (the location itself is of known size and format so the method knows how to decode it) and some meta data so the method knows the actual type of the value - wrapping the value with metadata and providing it's memory location is called (surprise, surprise) "boxing"
So, anytime you pass a value using a parameter/variable/whatever that is not the exact type the system has to box the value or the receiver wouldn't know much memory the value really uses and how to decode that memory from a sequence of bits back to a number or structure.
This only applies to value types because reference types are always passed by using the memory location (the memory location is called a "reference" in .net).