25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: memory.c,v 1.202 2007/04/28 09:19:51 debug Exp $ |
* $Id: memory.c,v 1.204 2007/06/15 17:02:38 debug Exp $ |
29 |
* |
* |
30 |
* Functions for handling the memory of an emulated machine. |
* Functions for handling the memory of an emulated machine. |
31 |
*/ |
*/ |
130 |
" environment.\n"); |
" environment.\n"); |
131 |
exit(1); |
exit(1); |
132 |
#else |
#else |
133 |
p = malloc(s); |
CHECK_ALLOCATION(p = malloc(s)); |
|
if (p == NULL) { |
|
|
fprintf(stderr, "out of memory\n"); |
|
|
exit(1); |
|
|
} |
|
134 |
memset(p, 0, s); |
memset(p, 0, s); |
135 |
#endif |
#endif |
136 |
} |
} |
154 |
int max_bits = MAX_BITS; |
int max_bits = MAX_BITS; |
155 |
size_t s; |
size_t s; |
156 |
|
|
157 |
mem = malloc(sizeof(struct memory)); |
CHECK_ALLOCATION(mem = malloc(sizeof(struct memory))); |
|
if (mem == NULL) { |
|
|
fprintf(stderr, "out of memory\n"); |
|
|
exit(1); |
|
|
} |
|
|
|
|
158 |
memset(mem, 0, sizeof(struct memory)); |
memset(mem, 0, sizeof(struct memory)); |
159 |
|
|
160 |
/* Check bits_per_pagetable and bits_per_memblock for sanity: */ |
/* Check bits_per_pagetable and bits_per_memblock for sanity: */ |
174 |
mem->pagetable = (unsigned char *) mmap(NULL, s, |
mem->pagetable = (unsigned char *) mmap(NULL, s, |
175 |
PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); |
PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); |
176 |
if (mem->pagetable == NULL) { |
if (mem->pagetable == NULL) { |
177 |
mem->pagetable = malloc(s); |
CHECK_ALLOCATION(mem->pagetable = malloc(s)); |
|
if (mem->pagetable == NULL) { |
|
|
fprintf(stderr, "out of memory\n"); |
|
|
exit(1); |
|
|
} |
|
178 |
memset(mem->pagetable, 0, s); |
memset(mem->pagetable, 0, s); |
179 |
} |
} |
180 |
|
|
413 |
|
|
414 |
mem->n_mmapped_devices++; |
mem->n_mmapped_devices++; |
415 |
|
|
416 |
mem->devices = realloc(mem->devices, sizeof(struct memory_device) |
CHECK_ALLOCATION(mem->devices = realloc(mem->devices, |
417 |
* mem->n_mmapped_devices); |
sizeof(struct memory_device) * mem->n_mmapped_devices)); |
|
if (mem->devices == NULL) { |
|
|
fprintf(stderr, "out of memory\n"); |
|
|
exit(1); |
|
|
} |
|
418 |
|
|
419 |
/* Make space for the new entry: */ |
/* Make space for the new entry: */ |
420 |
if (newi + 1 != mem->n_mmapped_devices) |
if (newi + 1 != mem->n_mmapped_devices) |
422 |
sizeof(struct memory_device) |
sizeof(struct memory_device) |
423 |
* (mem->n_mmapped_devices - newi - 1)); |
* (mem->n_mmapped_devices - newi - 1)); |
424 |
|
|
425 |
mem->devices[newi].name = strdup(device_name); |
CHECK_ALLOCATION(mem->devices[newi].name = strdup(device_name)); |
426 |
mem->devices[newi].baseaddr = baseaddr; |
mem->devices[newi].baseaddr = baseaddr; |
427 |
mem->devices[newi].endaddr = baseaddr + len; |
mem->devices[newi].endaddr = baseaddr + len; |
428 |
mem->devices[newi].length = len; |
mem->devices[newi].length = len; |
429 |
mem->devices[newi].flags = flags; |
mem->devices[newi].flags = flags; |
430 |
mem->devices[newi].dyntrans_data = dyntrans_data; |
mem->devices[newi].dyntrans_data = dyntrans_data; |
431 |
|
|
|
if (mem->devices[newi].name == NULL) { |
|
|
fprintf(stderr, "out of memory\n"); |
|
|
exit(1); |
|
|
} |
|
|
|
|
432 |
if (flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK) |
if (flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK) |
433 |
&& !(flags & DM_EMULATED_RAM) && dyntrans_data == NULL) { |
&& !(flags & DM_EMULATED_RAM) && dyntrans_data == NULL) { |
434 |
fatal("\nERROR: Device dyntrans access, but dyntrans_data" |
fatal("\nERROR: Device dyntrans access, but dyntrans_data" |
541 |
table[entry] = (void *) mmap(NULL, alloclen, |
table[entry] = (void *) mmap(NULL, alloclen, |
542 |
PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); |
PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); |
543 |
if (table[entry] == NULL) { |
if (table[entry] == NULL) { |
544 |
table[entry] = malloc(alloclen); |
CHECK_ALLOCATION(table[entry] = malloc(alloclen)); |
|
if (table[entry] == NULL) { |
|
|
fatal("out of memory\n"); |
|
|
exit(1); |
|
|
} |
|
545 |
memset(table[entry], 0, alloclen); |
memset(table[entry], 0, alloclen); |
546 |
} |
} |
547 |
} |
} |
654 |
} |
} |
655 |
} |
} |
656 |
|
|
657 |
|
|
658 |
|
/* |
659 |
|
* dump_mem_string(): |
660 |
|
* |
661 |
|
* Dump the contents of emulated RAM as readable text. Bytes that aren't |
662 |
|
* readable are dumped in [xx] notation, where xx is in hexadecimal. |
663 |
|
* Dumping ends after DUMP_MEM_STRING_MAX bytes, or when a terminating |
664 |
|
* zero byte is found. |
665 |
|
*/ |
666 |
|
#define DUMP_MEM_STRING_MAX 45 |
667 |
|
void dump_mem_string(struct cpu *cpu, uint64_t addr) |
668 |
|
{ |
669 |
|
int i; |
670 |
|
for (i=0; i<DUMP_MEM_STRING_MAX; i++) { |
671 |
|
unsigned char ch = '\0'; |
672 |
|
|
673 |
|
cpu->memory_rw(cpu, cpu->mem, addr + i, &ch, sizeof(ch), |
674 |
|
MEM_READ, CACHE_DATA | NO_EXCEPTIONS); |
675 |
|
if (ch == '\0') |
676 |
|
return; |
677 |
|
if (ch >= ' ' && ch < 126) |
678 |
|
debug("%c", ch); |
679 |
|
else |
680 |
|
debug("[%02x]", ch); |
681 |
|
} |
682 |
|
} |
683 |
|
|
684 |
|
|
685 |
|
/* |
686 |
|
* store_byte(): |
687 |
|
* |
688 |
|
* Stores a byte in emulated ram. (Helper function.) |
689 |
|
*/ |
690 |
|
void store_byte(struct cpu *cpu, uint64_t addr, uint8_t data) |
691 |
|
{ |
692 |
|
if ((addr >> 32) == 0) |
693 |
|
addr = (int64_t)(int32_t)addr; |
694 |
|
cpu->memory_rw(cpu, cpu->mem, |
695 |
|
addr, &data, sizeof(data), MEM_WRITE, CACHE_DATA); |
696 |
|
} |
697 |
|
|
698 |
|
|
699 |
|
/* |
700 |
|
* store_string(): |
701 |
|
* |
702 |
|
* Stores chars into emulated RAM until a zero byte (string terminating |
703 |
|
* character) is found. The zero byte is also copied. |
704 |
|
* (strcpy()-like helper function, host-RAM-to-emulated-RAM.) |
705 |
|
*/ |
706 |
|
void store_string(struct cpu *cpu, uint64_t addr, char *s) |
707 |
|
{ |
708 |
|
do { |
709 |
|
store_byte(cpu, addr++, *s); |
710 |
|
} while (*s++); |
711 |
|
} |
712 |
|
|
713 |
|
|
714 |
|
/* |
715 |
|
* add_environment_string(): |
716 |
|
* |
717 |
|
* Like store_string(), but advances the pointer afterwards. The most |
718 |
|
* obvious use is to place a number of strings (such as environment variable |
719 |
|
* strings) after one-another in emulated memory. |
720 |
|
*/ |
721 |
|
void add_environment_string(struct cpu *cpu, char *s, uint64_t *addr) |
722 |
|
{ |
723 |
|
store_string(cpu, *addr, s); |
724 |
|
(*addr) += strlen(s) + 1; |
725 |
|
} |
726 |
|
|
727 |
|
|
728 |
|
/* |
729 |
|
* add_environment_string_dual(): |
730 |
|
* |
731 |
|
* Add "dual" environment strings, one for the variable name and one for the |
732 |
|
* value, and update pointers afterwards. |
733 |
|
*/ |
734 |
|
void add_environment_string_dual(struct cpu *cpu, |
735 |
|
uint64_t *ptrp, uint64_t *addrp, char *s1, char *s2) |
736 |
|
{ |
737 |
|
uint64_t ptr = *ptrp, addr = *addrp; |
738 |
|
|
739 |
|
store_32bit_word(cpu, ptr, addr); |
740 |
|
ptr += sizeof(uint32_t); |
741 |
|
if (addr != 0) { |
742 |
|
store_string(cpu, addr, s1); |
743 |
|
addr += strlen(s1) + 1; |
744 |
|
} |
745 |
|
store_32bit_word(cpu, ptr, addr); |
746 |
|
ptr += sizeof(uint32_t); |
747 |
|
if (addr != 0) { |
748 |
|
store_string(cpu, addr, s2); |
749 |
|
addr += strlen(s2) + 1; |
750 |
|
} |
751 |
|
|
752 |
|
*ptrp = ptr; |
753 |
|
*addrp = addr; |
754 |
|
} |
755 |
|
|
756 |
|
|
757 |
|
/* |
758 |
|
* store_64bit_word(): |
759 |
|
* |
760 |
|
* Stores a 64-bit word in emulated RAM. Byte order is taken into account. |
761 |
|
* Helper function. |
762 |
|
*/ |
763 |
|
int store_64bit_word(struct cpu *cpu, uint64_t addr, uint64_t data64) |
764 |
|
{ |
765 |
|
unsigned char data[8]; |
766 |
|
if ((addr >> 32) == 0) |
767 |
|
addr = (int64_t)(int32_t)addr; |
768 |
|
data[0] = (data64 >> 56) & 255; |
769 |
|
data[1] = (data64 >> 48) & 255; |
770 |
|
data[2] = (data64 >> 40) & 255; |
771 |
|
data[3] = (data64 >> 32) & 255; |
772 |
|
data[4] = (data64 >> 24) & 255; |
773 |
|
data[5] = (data64 >> 16) & 255; |
774 |
|
data[6] = (data64 >> 8) & 255; |
775 |
|
data[7] = (data64) & 255; |
776 |
|
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { |
777 |
|
int tmp = data[0]; data[0] = data[7]; data[7] = tmp; |
778 |
|
tmp = data[1]; data[1] = data[6]; data[6] = tmp; |
779 |
|
tmp = data[2]; data[2] = data[5]; data[5] = tmp; |
780 |
|
tmp = data[3]; data[3] = data[4]; data[4] = tmp; |
781 |
|
} |
782 |
|
return cpu->memory_rw(cpu, cpu->mem, |
783 |
|
addr, data, sizeof(data), MEM_WRITE, CACHE_DATA); |
784 |
|
} |
785 |
|
|
786 |
|
|
787 |
|
/* |
788 |
|
* store_32bit_word(): |
789 |
|
* |
790 |
|
* Stores a 32-bit word in emulated RAM. Byte order is taken into account. |
791 |
|
* (This function takes a 64-bit word as argument, to suppress some |
792 |
|
* warnings, but only the lowest 32 bits are used.) |
793 |
|
*/ |
794 |
|
int store_32bit_word(struct cpu *cpu, uint64_t addr, uint64_t data32) |
795 |
|
{ |
796 |
|
unsigned char data[4]; |
797 |
|
|
798 |
|
data[0] = (data32 >> 24) & 255; |
799 |
|
data[1] = (data32 >> 16) & 255; |
800 |
|
data[2] = (data32 >> 8) & 255; |
801 |
|
data[3] = (data32) & 255; |
802 |
|
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { |
803 |
|
int tmp = data[0]; data[0] = data[3]; data[3] = tmp; |
804 |
|
tmp = data[1]; data[1] = data[2]; data[2] = tmp; |
805 |
|
} |
806 |
|
return cpu->memory_rw(cpu, cpu->mem, |
807 |
|
addr, data, sizeof(data), MEM_WRITE, CACHE_DATA); |
808 |
|
} |
809 |
|
|
810 |
|
|
811 |
|
/* |
812 |
|
* store_16bit_word(): |
813 |
|
* |
814 |
|
* Stores a 16-bit word in emulated RAM. Byte order is taken into account. |
815 |
|
* (This function takes a 64-bit word as argument, to suppress some |
816 |
|
* warnings, but only the lowest 16 bits are used.) |
817 |
|
*/ |
818 |
|
int store_16bit_word(struct cpu *cpu, uint64_t addr, uint64_t data16) |
819 |
|
{ |
820 |
|
unsigned char data[2]; |
821 |
|
|
822 |
|
data[0] = (data16 >> 8) & 255; |
823 |
|
data[1] = (data16) & 255; |
824 |
|
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { |
825 |
|
int tmp = data[0]; data[0] = data[1]; data[1] = tmp; |
826 |
|
} |
827 |
|
return cpu->memory_rw(cpu, cpu->mem, |
828 |
|
addr, data, sizeof(data), MEM_WRITE, CACHE_DATA); |
829 |
|
} |
830 |
|
|
831 |
|
|
832 |
|
/* |
833 |
|
* store_buf(): |
834 |
|
* |
835 |
|
* memcpy()-like helper function, from host RAM to emulated RAM. |
836 |
|
*/ |
837 |
|
void store_buf(struct cpu *cpu, uint64_t addr, char *s, size_t len) |
838 |
|
{ |
839 |
|
size_t psize = 1024; /* 1024 256 64 16 4 1 */ |
840 |
|
|
841 |
|
while (len != 0) { |
842 |
|
if ((addr & (psize-1)) == 0) { |
843 |
|
while (len >= psize) { |
844 |
|
cpu->memory_rw(cpu, cpu->mem, addr, |
845 |
|
(unsigned char *)s, psize, MEM_WRITE, |
846 |
|
CACHE_DATA); |
847 |
|
addr += psize; |
848 |
|
s += psize; |
849 |
|
len -= psize; |
850 |
|
} |
851 |
|
} |
852 |
|
psize >>= 2; |
853 |
|
} |
854 |
|
|
855 |
|
while (len-- != 0) |
856 |
|
store_byte(cpu, addr++, *s++); |
857 |
|
} |
858 |
|
|
859 |
|
|
860 |
|
/* |
861 |
|
* store_pointer_and_advance(): |
862 |
|
* |
863 |
|
* Stores a 32-bit or 64-bit pointer in emulated RAM, and advances the |
864 |
|
* target address. (Useful for e.g. ARCBIOS environment initialization.) |
865 |
|
*/ |
866 |
|
void store_pointer_and_advance(struct cpu *cpu, uint64_t *addrp, |
867 |
|
uint64_t data, int flag64) |
868 |
|
{ |
869 |
|
uint64_t addr = *addrp; |
870 |
|
if (flag64) { |
871 |
|
store_64bit_word(cpu, addr, data); |
872 |
|
addr += 8; |
873 |
|
} else { |
874 |
|
store_32bit_word(cpu, addr, data); |
875 |
|
addr += 4; |
876 |
|
} |
877 |
|
*addrp = addr; |
878 |
|
} |
879 |
|
|
880 |
|
|
881 |
|
/* |
882 |
|
* load_64bit_word(): |
883 |
|
* |
884 |
|
* Helper function. Emulated byte order is taken into account. |
885 |
|
*/ |
886 |
|
uint64_t load_64bit_word(struct cpu *cpu, uint64_t addr) |
887 |
|
{ |
888 |
|
unsigned char data[8]; |
889 |
|
|
890 |
|
cpu->memory_rw(cpu, cpu->mem, |
891 |
|
addr, data, sizeof(data), MEM_READ, CACHE_DATA); |
892 |
|
|
893 |
|
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { |
894 |
|
int tmp = data[0]; data[0] = data[7]; data[7] = tmp; |
895 |
|
tmp = data[1]; data[1] = data[6]; data[6] = tmp; |
896 |
|
tmp = data[2]; data[2] = data[5]; data[5] = tmp; |
897 |
|
tmp = data[3]; data[3] = data[4]; data[4] = tmp; |
898 |
|
} |
899 |
|
|
900 |
|
return |
901 |
|
((uint64_t)data[0] << 56) + ((uint64_t)data[1] << 48) + |
902 |
|
((uint64_t)data[2] << 40) + ((uint64_t)data[3] << 32) + |
903 |
|
((uint64_t)data[4] << 24) + ((uint64_t)data[5] << 16) + |
904 |
|
((uint64_t)data[6] << 8) + (uint64_t)data[7]; |
905 |
|
} |
906 |
|
|
907 |
|
|
908 |
|
/* |
909 |
|
* load_32bit_word(): |
910 |
|
* |
911 |
|
* Helper function. Emulated byte order is taken into account. |
912 |
|
*/ |
913 |
|
uint32_t load_32bit_word(struct cpu *cpu, uint64_t addr) |
914 |
|
{ |
915 |
|
unsigned char data[4]; |
916 |
|
|
917 |
|
cpu->memory_rw(cpu, cpu->mem, |
918 |
|
addr, data, sizeof(data), MEM_READ, CACHE_DATA); |
919 |
|
|
920 |
|
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { |
921 |
|
int tmp = data[0]; data[0] = data[3]; data[3] = tmp; |
922 |
|
tmp = data[1]; data[1] = data[2]; data[2] = tmp; |
923 |
|
} |
924 |
|
|
925 |
|
return (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]; |
926 |
|
} |
927 |
|
|
928 |
|
|
929 |
|
/* |
930 |
|
* load_16bit_word(): |
931 |
|
* |
932 |
|
* Helper function. Emulated byte order is taken into account. |
933 |
|
*/ |
934 |
|
uint16_t load_16bit_word(struct cpu *cpu, uint64_t addr) |
935 |
|
{ |
936 |
|
unsigned char data[2]; |
937 |
|
|
938 |
|
cpu->memory_rw(cpu, cpu->mem, |
939 |
|
addr, data, sizeof(data), MEM_READ, CACHE_DATA); |
940 |
|
|
941 |
|
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { |
942 |
|
int tmp = data[0]; data[0] = data[1]; data[1] = tmp; |
943 |
|
} |
944 |
|
|
945 |
|
return (data[0] << 8) + data[1]; |
946 |
|
} |
947 |
|
|
948 |
|
|
949 |
|
/* |
950 |
|
* store_64bit_word_in_host(): |
951 |
|
* |
952 |
|
* Stores a 64-bit word in the _host's_ RAM. Emulated byte order is taken |
953 |
|
* into account. This is useful when building structs in the host's RAM |
954 |
|
* which will later be copied into emulated RAM. |
955 |
|
*/ |
956 |
|
void store_64bit_word_in_host(struct cpu *cpu, |
957 |
|
unsigned char *data, uint64_t data64) |
958 |
|
{ |
959 |
|
data[0] = (data64 >> 56) & 255; |
960 |
|
data[1] = (data64 >> 48) & 255; |
961 |
|
data[2] = (data64 >> 40) & 255; |
962 |
|
data[3] = (data64 >> 32) & 255; |
963 |
|
data[4] = (data64 >> 24) & 255; |
964 |
|
data[5] = (data64 >> 16) & 255; |
965 |
|
data[6] = (data64 >> 8) & 255; |
966 |
|
data[7] = (data64) & 255; |
967 |
|
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { |
968 |
|
int tmp = data[0]; data[0] = data[7]; data[7] = tmp; |
969 |
|
tmp = data[1]; data[1] = data[6]; data[6] = tmp; |
970 |
|
tmp = data[2]; data[2] = data[5]; data[5] = tmp; |
971 |
|
tmp = data[3]; data[3] = data[4]; data[4] = tmp; |
972 |
|
} |
973 |
|
} |
974 |
|
|
975 |
|
|
976 |
|
/* |
977 |
|
* store_32bit_word_in_host(): |
978 |
|
* |
979 |
|
* See comment for store_64bit_word_in_host(). |
980 |
|
* |
981 |
|
* (Note: The data32 parameter is a uint64_t. This is done to suppress |
982 |
|
* some warnings.) |
983 |
|
*/ |
984 |
|
void store_32bit_word_in_host(struct cpu *cpu, |
985 |
|
unsigned char *data, uint64_t data32) |
986 |
|
{ |
987 |
|
data[0] = (data32 >> 24) & 255; |
988 |
|
data[1] = (data32 >> 16) & 255; |
989 |
|
data[2] = (data32 >> 8) & 255; |
990 |
|
data[3] = (data32) & 255; |
991 |
|
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { |
992 |
|
int tmp = data[0]; data[0] = data[3]; data[3] = tmp; |
993 |
|
tmp = data[1]; data[1] = data[2]; data[2] = tmp; |
994 |
|
} |
995 |
|
} |
996 |
|
|
997 |
|
|
998 |
|
/* |
999 |
|
* store_16bit_word_in_host(): |
1000 |
|
* |
1001 |
|
* See comment for store_64bit_word_in_host(). |
1002 |
|
*/ |
1003 |
|
void store_16bit_word_in_host(struct cpu *cpu, |
1004 |
|
unsigned char *data, uint16_t data16) |
1005 |
|
{ |
1006 |
|
data[0] = (data16 >> 8) & 255; |
1007 |
|
data[1] = (data16) & 255; |
1008 |
|
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { |
1009 |
|
int tmp = data[0]; data[0] = data[1]; data[1] = tmp; |
1010 |
|
} |
1011 |
|
} |
1012 |
|
|