1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
#ifndef VIRTADDR_H
#define VIRTADDR_H
/* Segment selectors as used in our protected-mode GDTs.
*
* Don't change these unless you really know what you're doing.
*/
#define VIRTUAL_CS 0x08
#define VIRTUAL_DS 0x10
#define PHYSICAL_CS 0x18
#define PHYSICAL_DS 0x20
#define REAL_CS 0x28
#define REAL_DS 0x30
#if 0
#define LONG_CS 0x38
#define LONG_DS 0x40
#endif
#ifndef ASSEMBLY
#include "stdint.h"
#include "string.h"
#ifndef KEEP_IT_REAL
/*
* Without -DKEEP_IT_REAL, we are in 32-bit protected mode with a
* fixed link address but an unknown physical start address. Our GDT
* sets up code and data segments with an offset of virt_offset, so
* that link-time addresses can still work.
*
*/
/* C-callable function prototypes */
extern void relocate_to ( uint32_t new_phys_addr );
/* Variables in virtaddr.S */
extern unsigned long virt_offset;
/*
* Convert between virtual and physical addresses
*
*/
static inline unsigned long virt_to_phys ( volatile const void *virt_addr ) {
return ( ( unsigned long ) virt_addr ) + virt_offset;
}
static inline void * phys_to_virt ( unsigned long phys_addr ) {
return ( void * ) ( phys_addr - virt_offset );
}
static inline void copy_to_phys ( physaddr_t dest, const void *src,
size_t len ) {
memcpy ( phys_to_virt ( dest ), src, len );
}
static inline void copy_from_phys ( void *dest, physaddr_t src, size_t len ) {
memcpy ( dest, phys_to_virt ( src ), len );
}
static inline void copy_phys_to_phys ( physaddr_t dest, physaddr_t src,
size_t len ) {
memcpy ( phys_to_virt ( dest ), phys_to_virt ( src ), len );
}
#else /* KEEP_IT_REAL */
/*
* With -DKEEP_IT_REAL, we are in 16-bit real mode with fixed link
* addresses and a segmented memory model. We have separate code and
* data segments.
*
* Because we may be called in 16-bit protected mode (damn PXE spec),
* we cannot simply assume that physical = segment * 16 + offset.
* Instead, we have to look up the physical start address of the
* segment in the !PXE structure. We have to assume that
* virt_to_phys() is called only on pointers within the data segment,
* because nothing passes segment information to us.
*
* We don't implement phys_to_virt at all, because there will be many
* addresses that simply cannot be reached via a virtual address when
* the virtual address space is limited to 64kB!
*/
static inline unsigned long virt_to_phys ( volatile const void *virt_addr ) {
/* Cheat: just for now, do the segment*16+offset calculation */
uint16_t ds;
__asm__ ( "movw %%ds, %%ax" : "=a" ( ds ) : );
return ( 16 * ds + ( ( unsigned long ) virt_addr ) );
}
/* Define it as a deprecated function so that we get compile-time
* warnings, rather than just the link-time errors.
*/
extern void * phys_to_virt ( unsigned long phys_addr )
__attribute__ ((deprecated));
#endif /* KEEP_IT_REAL */
#endif /* ASSEMBLY */
#endif /* VIRTADDR_H */
|